@sellable/mcp 0.1.200 → 0.1.202

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -119,11 +119,29 @@ blocker.
119
119
  - Engagement-source personalization is a special case, not the default opener.
120
120
  Do not write `saw you {{engagement_context}} on {{post_context}}`, `saw you
121
121
  reacted to`, `saw you engaging with`, or equivalent source-citation copy as a
122
- default hook. Only refer to engagement when the line is self-aware and
123
- low-certainty, for example: `you might not remember the thread, but I found
124
- you through a [topic] discussion and your [observable role/company context]
125
- looked close to [problem]`. Otherwise omit the engagement signal and use
126
- role/company/problem context.
122
+ default hook. For LinkedIn-post-sourced campaigns, you may reference the
123
+ source when it explains why the note exists, but keep it topic-level, not
124
+ activity-log-level. Good: `saw you in a few conversations around [topic], so
125
+ hope this is relevant`, `saw you in a few conversations about [topic], so
126
+ may be off, but this seemed relevant`, `saw you might be interested in [topic],
127
+ so hope this is relevant`, `hope this is relevant if [topic] is on your plate`,
128
+ or `saw you raise your hand for [topic], so figured this was (hopefully) worth sending`.
129
+ The cheekier `saw you raise your hand for [topic] (creepy to reach out based
130
+ on that, i know) - but this felt too on the nose to ignore` version is also
131
+ allowed when the sender's voice can carry it. Bad: `you commented on...`, `you reacted
132
+ to...`, `saw you engaging with...`, `your LinkedIn activity...`, `you might
133
+ not remember the thread...`, or `found you through [source] and your role
134
+ looked close...`. Otherwise omit the engagement signal and use role/company/problem context.
135
+ - Do not use a PS to defend the source. Lines like `p.s. if the source thread
136
+ was just casual reading, ignore me` or `only reaching out where the role and
137
+ topic looked close` are blocked. If the source is too weak, omit it.
138
+ - Do not assert fit from title/company. `Your [role] role at [company] looked
139
+ close to this problem` is blocked. Keep the apologetic uncertainty instead:
140
+ `may be off, but if [workflow] is anywhere near your lane...`.
141
+ - Low-pressure relevance opt-outs are allowed when they do not defend the
142
+ source: `p.s. if this is nowhere near your outbound workflow, ignore me`.
143
+ - Do not use `Caught` as opener language. It reads unnatural in LinkedIn
144
+ outreach.
127
145
  - Do not describe the sender in third person inside the outbound message.
128
146
  Lines like `p.s. Saju's angle is...`, `Christian's angle is...`, or
129
147
  `[sender]'s approach is...` are internal notes leaking into copy. If the point
@@ -38,6 +38,8 @@ type WorkflowTableMessageStats = {
38
38
  type NavigationDebugPayload = Record<string, unknown>;
39
39
  export declare function logNavigationDebug(event: string, payload?: NavigationDebugPayload, campaignId?: string | null): void;
40
40
  type CreateCampaignStepId = "campaign-created" | "pick-provider" | "provider-search" | "confirm-lead-list" | "filter-rules" | "messages" | "settings" | "sequence" | "send" | "running";
41
+ export type GeneratedMessageApprovalGateMissing = "generatedMessages" | "approvedGeneratedMessage";
42
+ export declare function getGeneratedMessageApprovalGateMissing(stats?: WorkflowTableMessageStats | null, statsChecked?: boolean): GeneratedMessageApprovalGateMissing[];
41
43
  export declare const navigationToolDefinitions: {
42
44
  name: string;
43
45
  description: string;
@@ -251,12 +251,9 @@ function getApprovedGeneratedMessageCount(stats) {
251
251
  return null;
252
252
  return stats.approvedCount ?? null;
253
253
  }
254
- function checkMessages(campaign, stats, statsChecked = false) {
254
+ export function getGeneratedMessageApprovalGateMissing(stats, statsChecked = false) {
255
255
  const missing = [];
256
- if (!hasApprovedMessageTemplate(campaign)) {
257
- missing.push("approvedMessageTemplate");
258
- }
259
- if (statsChecked && hasApprovedMessageTemplate(campaign)) {
256
+ if (statsChecked) {
260
257
  const generatedCount = getGeneratedMessageCount(stats) ?? 0;
261
258
  const approvedCount = getApprovedGeneratedMessageCount(stats) ?? 0;
262
259
  if (generatedCount <= 0) {
@@ -266,6 +263,10 @@ function checkMessages(campaign, stats, statsChecked = false) {
266
263
  missing.push("approvedGeneratedMessage");
267
264
  }
268
265
  }
266
+ return missing;
267
+ }
268
+ function checkMessages(stats, statsChecked = false) {
269
+ const missing = getGeneratedMessageApprovalGateMissing(stats, statsChecked);
269
270
  return { stepId: "messages", missing };
270
271
  }
271
272
  function checkSettings(campaign) {
@@ -541,7 +542,7 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
541
542
  }
542
543
  const evaluateTailState = shouldEvaluateTailState(campaign);
543
544
  if (evaluateTailState) {
544
- checks.push(checkMessages(campaign, options.messageStats ?? null, options.messageStatsChecked === true), checkSettings(campaign), checkSequence(campaign));
545
+ checks.push(checkMessages(options.messageStats ?? null, options.messageStatsChecked === true), checkSettings(campaign), checkSequence(campaign));
545
546
  }
546
547
  let computedStep = "campaign-created";
547
548
  let blockedAt = null;
@@ -564,11 +565,9 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
564
565
  computedStep = isRunningCampaign(campaign) ? "running" : "send";
565
566
  }
566
567
  const stepForHeadless = blockedAt ?? computedStep;
567
- const waitingOnMessageTemplateAfterFilters = blockedAt === "messages" &&
568
- campaign.enableICPFilters === true &&
569
- hasActiveRubrics(campaign) &&
570
- !hasApprovedMessageTemplate(campaign);
571
- const waitingOnGeneratedMessageApproval = blockedAt === "messages" && hasApprovedMessageTemplate(campaign);
568
+ const waitingOnGeneratedMessageApproval = blockedAt === "messages" &&
569
+ (missing.includes("generatedMessages") ||
570
+ missing.includes("approvedGeneratedMessage"));
572
571
  const expectedHeadlessStep = stepForHeadless === "campaign-created"
573
572
  ? "create-offer"
574
573
  : stepForHeadless === "provider-search"
@@ -576,11 +575,9 @@ export function computeCampaignNavigationStateFromCampaign(campaign, options) {
576
575
  : stepForHeadless === "filter-rules"
577
576
  ? "create-icp-rubric"
578
577
  : stepForHeadless === "messages"
579
- ? waitingOnMessageTemplateAfterFilters
580
- ? "apply-icp-rubric"
581
- : waitingOnGeneratedMessageApproval
582
- ? "auto-execute-messaging"
583
- : "messages"
578
+ ? waitingOnGeneratedMessageApproval
579
+ ? "auto-execute-messaging"
580
+ : "messages"
584
581
  : stepForHeadless === "settings"
585
582
  ? "settings"
586
583
  : stepForHeadless === "sequence"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.200",
3
+ "version": "0.1.202",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -104,6 +104,10 @@ message to you (yes, it's that meta)
104
104
  p.s. yes, this message was entirely written and sent via claude code 😊
105
105
  ```
106
106
 
107
+ The softer alternate hook is also allowed when the message needs less cheek:
108
+ `saw you raise your hand for claude + gtm, so figured this was (hopefully)
109
+ worth sending.`
110
+
107
111
  Note what the tokens DO:
108
112
 
109
113
  - `[PERSONALIZED REASON - their team size, role, or why they're a perfect fit]`
@@ -126,10 +130,15 @@ should err toward explicit:
126
130
 
127
131
  ```text
128
132
  [PERSONALIZATION_LINE — write ONE short sentence (8-15 words) that anchors
129
- this message to {{first_name}} as a person. Name what they personally DO,
130
- write about, focus on, or build TOWARD (not what their company SELLS).
131
- DO: use verb-led shapes "Saw your work helping X", "Your writing on Y
132
- caught my eye", "Your focus on Z is rare in this segment".
133
+ this message to why it might matter now. Connect one observed role/company/
134
+ activity signal to the buyer problem or offer.
135
+ DO: use low-certainty bridge shapes: "hope this is relevant if X is live",
136
+ "saw you might be interested in X, so hope this is relevant", or "figured this
137
+ might matter if X is on your plate". For LinkedIn-post-sourced campaigns, a
138
+ topic-level bridge like "saw you in a few conversations around X, so hope this
139
+ is relevant" is allowed.
140
+ DON'T: recap their resume, list companies, or say their "background stood
141
+ out" — that tells them about themselves without creating a reason for the note.
133
142
  DON'T: name a product their company sells ("your dashboard for X", "your
134
143
  platform for Y") — they BUILD the product, they don't have one.
135
144
  DON'T: use source-citation phrasing ("Saw your post about", "Your bio
@@ -20,8 +20,10 @@ prospect's context.
20
20
  Examples:
21
21
 
22
22
  - Good: "saw you're hiring AE talent after opening the Austin office"
23
- - Good: "noticed your team has been talking more openly about runtime exposure"
24
- - Good: "looks like you're still growing through founder-led content"
23
+ - Good: "hope this is relevant if Austin hiring is still live"
24
+ - Good: "saw you might be interested in runtime exposure, so hope this is relevant"
25
+ - Good: "saw you in a few conversations around runtime exposure, so hope this is relevant"
26
+ - Good: "figured this might matter if founder-led content is still driving growth"
25
27
 
26
28
  Why these work:
27
29
 
@@ -58,13 +60,17 @@ Why these fail:
58
60
 
59
61
  Smooth:
60
62
 
61
- - "not sure if this is relevant but it looks like you're pushing into enterprise accounts now"
62
- - "saw the post on AI exposure and thought this might actually be relevant"
63
+ - "hope this is relevant if enterprise is still the push"
64
+ - "saw you might be interested in AI exposure, so hope this is relevant"
65
+ - "saw you in a few conversations around AI exposure, so hope this is relevant"
66
+ - "figured this might matter if outbound is part of the expansion plan"
63
67
 
64
68
  Awkward:
65
69
 
66
70
  - "not sure if this is relevant but according to your recent post you are pushing into enterprise accounts"
67
71
  - "I saw on LinkedIn that you recently posted about AI exposure and therefore wanted to contact you"
72
+ - "Your GTM and international growth work at Nas Daily and 1000media looked close to the kind of outbound work Sellable is built for"
73
+ - "Your background across creator media and market expansion stood out"
68
74
 
69
75
  ## Persona-Specific Notes
70
76
 
@@ -86,6 +92,8 @@ Revvix / security positioning:
86
92
  ## Red Flags
87
93
 
88
94
  - the token reads like CRM metadata
95
+ - the token only tells the prospect facts about themselves
96
+ - the token uses company names as decoration without a buyer-relevant bridge
89
97
  - the token makes the sentence longer without making it better
90
98
  - the token sounds like a compliment sandwich
91
99
  - the token could be swapped into any message without changing meaning
@@ -61,7 +61,8 @@ p.s. yes, this message was entirely written and sent via claude code 😊
61
61
 
62
62
  "saw you raise your hand for claude + gtm (creepy to reach out based on that, i know) - but this felt too on the nose to ignore."
63
63
 
64
- Uses parentheses (feels human, AI rarely writes this way). Self-aware about the signal without being apologetic.
64
+ Uses parentheses for self-awareness without being apologetic. Softer alternate:
65
+ "saw you raise your hand for claude + gtm, so figured this was (hopefully) worth sending."
65
66
 
66
67
  ## Product Line
67
68
 
@@ -33,21 +33,26 @@ think you'd have an opinion on..."`
33
33
 
34
34
  **Severity:** REJECT
35
35
 
36
- ## Tell #2 — Explicit recipient-fact reference in opener
36
+ ## Tell #2 — Plain source-citation recipient fact in opener
37
37
 
38
38
  **Pattern:** `Hey {{first_name}} — saw you posted...` / `Hey
39
39
  {{first_name}}, your X is...` / `I noticed your...` / `Saw the X you
40
- posted...` — opening sentence leads with a recipient-specific
41
- reference.
40
+ posted...` — opening sentence leads with a bare recipient-specific
41
+ reference and no self-aware reason the note might matter.
42
42
 
43
43
  **Why it's an AI tell:** Talking AT the recipient instead of WITH
44
- them. Real founders open with their own reality, not by
45
- interrogating the recipient's data feed. `"I noticed your..."` reads
46
- as scraped intel.
47
-
48
- **Allowed alternative:** Open with sender reality (Block 1); let
49
- recipient gravity show up in Block 3 as a LIGHT callback. Refer to
50
- their work CASUALLY without `"saw your X"`.
44
+ them. Real founders do not interrogate the recipient's data feed or
45
+ recite profile facts. `"I noticed your..."` reads as scraped intel.
46
+
47
+ **Allowed alternative:** Use a concise permissioned bridge:
48
+ `"Hope this is relevant if X is still live."`, `"Saw you might be
49
+ interested in X, so hope this is relevant."`, `"Saw you in a few
50
+ conversations around X, so hope this is relevant."` for LinkedIn-post-sourced
51
+ campaigns, or the self-aware
52
+ `"saw you raise your hand for X, so figured this was (hopefully) worth
53
+ sending"` or `"saw you raise your hand for X (creepy to reach out based
54
+ on that, i know) - but this felt too on the nose to ignore"` shapes when the
55
+ engagement source is the reason for the note.
51
56
 
52
57
  **Severity:** REJECT
53
58
 
@@ -238,6 +243,68 @@ reference-file text, brief-template text, prompt text, and audit
238
243
  notes are fine — this is a body-level output guard, not a
239
244
  general-prose style rule.
240
245
 
246
+ ## Tell #14 — Resume recap personalization bridge
247
+
248
+ **Pattern:** A personalization line that strings together prior
249
+ employers, roles, abstract tags, or a product-centered bridge without a
250
+ buyer-relevant reason. Example: `"Your GTM and international growth work
251
+ at Nas Daily and 1000media looked close to the kind of outbound work
252
+ Sellable is built for."`
253
+
254
+ **Why it's an AI tell:** It reads like a LinkedIn parser compressed a
255
+ profile into tags. Real senders do not tell prospects their own resume
256
+ back to them, then pivot to the product. The line is name-drop-heavy,
257
+ abstract, and swappable across hundreds of leads.
258
+
259
+ **Allowed alternative:** Use a short relevance hypothesis that connects
260
+ one observed signal to why the note may matter: `"Hope this is relevant
261
+ if market expansion is still on your plate."`, `"Saw you might be
262
+ interested in Claude + GTM, so hope this is relevant."`, or `"Saw you in
263
+ a few conversations around international growth, so hope this is relevant."`
264
+
265
+ **Severity:** REJECT
266
+
267
+ ## Tell #15 — Source-thread disclaimer
268
+
269
+ **Pattern:** `"You might not remember the thread, but I found you
270
+ through..."` in the opener, `"found you through [source] and your role
271
+ looked close..."`, or a PS like `"if the source thread was just casual
272
+ reading, ignore me"` / `"only reaching out where the role and topic
273
+ looked close."`
274
+
275
+ **Why it's an AI tell:** It exposes sourcing mechanics instead of
276
+ creating relevance. The message sounds like a lead scraper explaining
277
+ why it picked the recipient, then asking the recipient to forgive the
278
+ reach-out.
279
+
280
+ **Allowed alternative:** Use a concise topic-level bridge when the
281
+ source is meaningful, then continue with apologetic uncertainty:
282
+ `"Saw you in a few conversations about LinkedIn outreach, so may be
283
+ off, but this seemed relevant."` or `"Saw you in a few conversations
284
+ around LinkedIn outreach, so hope this is relevant."` If the source was
285
+ only casual reading or the role/topic connection is weak, omit the
286
+ personalization line and open from the buyer pain.
287
+
288
+ **Severity:** REJECT
289
+
290
+ ## Tell #16 — Assumptive title-fit opener
291
+
292
+ **Pattern:** `"Your enterprise sales role at Odoo looked close to this
293
+ outbound campaign problem."` / `"your [role] role at [company] looked
294
+ close to this problem."`
295
+
296
+ **Why it's an AI tell:** It turns title/company metadata into a fit
297
+ claim the recipient did not make. The line tells the buyer about
298
+ themselves and assumes the workflow belongs to them.
299
+
300
+ **Allowed alternative:** Keep the apologetic uncertainty without
301
+ asserting fit: `"May be off, but if outbound is anywhere near your
302
+ lane, this might be useful."` A low-pressure PS such as `"p.s. if this
303
+ is nowhere near your outbound workflow, ignore me"` is allowed when it
304
+ does not narrate the source.
305
+
306
+ **Severity:** REJECT
307
+
241
308
  ---
242
309
 
243
310
  ## How to add new tells
@@ -74,10 +74,12 @@ Revise or reject the sample when any of these happen.
74
74
  - **actions are implied, not stated** — e.g. "runs that chain as AI agents" when a clearer version would name the specific actions (verb + object, one per line)
75
75
  - **category-level opener used when a per-lead signal exists** — if `lead-sample.json` carries any per-lead signal (post, hire, visible tool, topic engagement), the opener must reference it. Category-level openers of shape `"Most [category] teams still do X by hand"` are only acceptable when zero per-lead signal is in the sample. When a category-level opener is used as fallback, Findings must flag it explicitly
76
76
  - **mind-reading from engagement signals** — a topic engagement, post, public activity, role, company, or hiring trigger does not prove buyer intent. Reject phrases like `"AI-GTM stack is clearly on your mind"`, `"you're clearly focused on..."`, `"obviously relevant"`, or `"already thinking about..."` unless that exact priority is explicitly present in `lead-sample.json`. Translate to low-certainty buyer context or omit the signal from copy.
77
- - **source-y signal narration** — reject `"saw you on..."`, `"saw you around..."`, `"saw you engaging with..."`, `"your LinkedIn activity..."`, or any line that makes the recipient feel watched unless the chosen archived motion is intentionally self-aware about the signal. Translate the signal into a natural buyer-context line or omit it.
77
+ - **source-y signal narration** — reject `"saw you on..."`, `"saw you engaging with..."`, `"you commented on..."`, `"your LinkedIn activity..."`, `"you might not remember the thread..."`, `"found you through [source] and your role looked close..."`, or any line that makes the recipient feel watched unless the chosen archived motion is intentionally self-aware about the signal. For LinkedIn-post-sourced campaigns, a topic-level bridge is allowed when it explains why the note exists and stays apologetically uncertain: `"saw you in a few conversations about [topic], so may be off, but this seemed relevant."` or `"saw you in a few conversations around [topic], so hope this is relevant."` Translate the signal into natural buyer context or omit it.
78
+ - **assumptive title-fit opener** — reject `"Your [role] role at [company] looked close to this problem"` or `"looked close to this outbound campaign problem"`. This asserts fit from title/company. Keep the apologetic uncertainty instead: `"may be off, but if [workflow] is anywhere near your lane..."`.
78
79
  - **internal-metric flex** — reject compute time, token/cache details, model names, agent-counts, orchestration internals, or similar process metrics unless the brief proves the buyer cares about that exact detail. `~5 min of compute per message` is not buyer value by itself.
79
80
  - **action lines are parallel (same subject, e.g. `It X` / `It Y` / `It Z`) but rendered as one-line paragraphs instead of bullets** — parallel action lines are the bullet case. One-line paragraphs are only for actions that carry a short narrative clause
80
81
  - **PS carries a second proof beat that doesn't answer a different objection** — the second beat must open a dimension beat #1 didn't address (e.g. technical reliability when beat #1 was operator empathy; named backing when beat #1 was founder track record). Default PS is ONE beat
82
+ - **apologetic source-thread PS** — reject `p.s. if the source thread was just casual reading, ignore me`, `only reaching out where the role and topic looked close`, or any PS that defends why the recipient was sourced. If the source is too weak, omit the personalization line. A relevance-risk PS such as `p.s. if this is nowhere near your outbound workflow, ignore me` is allowed because it lowers pressure without narrating the source.
81
83
  - **subject line uses the same banned glue jargon as the body** — any B2B compound noun the buyer wouldn't say naturally in conversation. Subject follows the same jargon rules as the body
82
84
  - **jargon that a 5th-grade reader could not parse** — any B2B compound noun the buyer wouldn't say naturally in conversation. Common examples across motions: "handoff", "rip-and-replace", "pane of glass", "single source of truth", "alert fatigue", "top of funnel", "time to hire". Keep product and tool names that the buyer recognizes; cut the glue language around them
83
85
  - em dashes in copy that is otherwise plainspoken
@@ -326,12 +328,12 @@ frame ("your BioRender post").
326
328
 
327
329
  ### Filter 7 — Anti-talk-at filter
328
330
 
329
- **Rule.** The OPENING SENTENCE must not lead with a
330
- recipient-specific reference. The opener must establish sender
331
- reality FIRST what we're building, who we are, why we're reaching
332
- out — before any callback to the recipient. A "talk-at" opener reads
333
- like a cold-scraper addressing a target; a "sender-first" opener
334
- reads like a founder introducing themselves.
331
+ **Rule.** The OPENING SENTENCE must not lead with a source-citation,
332
+ resume recap, or bare recipient fact. The opener can be sender-first
333
+ or permissioned relevance, but it must establish why the note might
334
+ matter. A "talk-at" opener reads like a cold-scraper addressing a
335
+ target; a good opener reads like a founder sending something that may
336
+ actually be relevant.
335
337
 
336
338
  **Detection patterns to REJECT as the opener (non-exhaustive):**
337
339
 
@@ -343,17 +345,35 @@ reads like a founder introducing themselves.
343
345
  - `Six months into your...`
344
346
  - `Your [company] post last month...`
345
347
  - `Just read your [X]...`
348
+ - `You might not remember the thread, but I found you through [source]...`
349
+ - `I found you through a LinkedIn outreach discussion and your [role] at [company] looked close to this problem.`
350
+ - `Caught your profile...`
351
+ - `Your GTM and international growth work at [Company A] and [Company B] looked close to what [Product] is built for.`
352
+ - `Your enterprise sales role at Odoo looked close to this outbound campaign problem.`
346
353
 
347
354
  Recipient-specific gravity MAY appear in body sentences 2-4 as a
348
355
  LIGHT callback (one casual sentence, no verbatim quote, no date
349
- reference), but never as the lede. The first impression must read
350
- as "a founder reaching out about something they built" — not
351
- "someone who scraped me."
356
+ reference), and MAY lead the opener only when it is a concise
357
+ permissioned bridge or intentionally self-aware engagement line. The
358
+ first impression must read as "this may be relevant" — not "someone
359
+ who scraped me."
352
360
 
353
- **Acceptable opener shapes (sender-first):**
361
+ **Acceptable opener shapes:**
354
362
 
355
363
  - `Hey {{first_name}}, I'm building [X] — [what it does in one plain
356
364
  sentence].`
365
+ - `Hey {{first_name}}, hope this is relevant if [buyer context] is
366
+ still on your plate.`
367
+ - `Hey {{first_name}}, may be off, but if [workflow] is anywhere near
368
+ your lane, this might be useful.`
369
+ - `Hey {{first_name}}, saw you might be interested in [topic], so hope
370
+ this is relevant.`
371
+ - `Hey {{first_name}}, saw you in a few conversations around [topic],
372
+ so hope this is relevant.`
373
+ - `Hey {{first_name}}, saw you raise your hand for [topic], so figured
374
+ this was (hopefully) worth sending.`
375
+ - `Hey {{first_name}}, saw you raise your hand for [topic] (creepy to
376
+ reach out based on that, i know) - but this felt too on the nose to ignore.`
357
377
  - `Hey {{first_name}}, quick one. My co-founder and I left [prior
358
378
  role] to build [X].`
359
379
  - `Hey {{first_name}}, reaching out because [one-line sender
@@ -170,10 +170,20 @@ writing the Token Fill Rules or any reusable template notes.
170
170
  `{{company}}`, or another noun-shaped token when the line needs judgment.
171
171
  - Use this shape for any hook, bridge, or row-specific relevance line:
172
172
  `[PERSONALIZATION_LINE — Intent: write one short sentence that anchors the
173
- note to the prospect's buyer-relevant activity. DO: name what they do, write
174
- about, focus on, or build toward. DON'T: name a product their company sells,
175
- use source-citation phrasing, or use generic nouns like "your work".
173
+ note to why this might matter now. DO: connect one observable role/company/
174
+ activity signal to the buyer problem or offer with low-certainty language like
175
+ "hope this is relevant if...", "saw you might be interested in...", "saw you in
176
+ a few conversations around...", or "figured this might matter if...". DON'T: recap
177
+ their resume, list companies, compliment their background, name a product their
178
+ company sells, use source-citation phrasing, or use generic nouns like "your
179
+ work".
176
180
  FALLBACK: if unsupported, omit the entire line.]`
181
+ - The rendered personalization line should usually be 6-14 words. If it needs
182
+ two clauses, multiple companies, or abstract tags like `GTM`, `international
183
+ growth`, and `outbound work` to make sense, it is probably analysis leakage,
184
+ not sendable copy.
185
+ - Personalization must not only tell the prospect about themselves. A good line
186
+ creates a reason for the note: observed context -> why this might be relevant.
177
187
  - The bracketed token belongs in the reusable template / token plan only. The
178
188
  rendered `Selected Winner` and sample messages must contain the composed
179
189
  sentence or no line at all; never show the bracket to the buyer.
@@ -313,17 +323,86 @@ artifact.**
313
323
  - `your team is obviously paying attention to...`
314
324
  - `you're already thinking about...`
315
325
  - `this is obviously relevant because...`
326
+ - `your {{role}} role at {{company}} looked close to this problem`
327
+ - `your {{role}} role at {{company}} looked close to this outbound campaign problem`
316
328
  - `saw you on {{recent_signal}}`
317
329
  - `saw you around {{recent_signal}}`
318
330
  - `saw you engaging with {{recent_signal}}`
319
331
 
320
332
  Safer shapes:
321
333
 
322
- - `not sure if this is relevant, but if {{signal_topic}} is part of what you're testing, this may be useful`
323
- - `this may be too specific, but the {{signal_topic}} angle felt close enough to send`
324
- - `if {{workflow_signal}} is relevant at {{company}}, this might be useful`
325
- - `thought this was worth sending because {{signal_topic}} touches the same problem`
326
- - `you might not remember the thread, but I found you through a {{signal_topic}} discussion and your {{observable_role_context}} looked close to {{problem_context}}`
334
+ - `hope this is relevant if {{signal_topic}} is part of the plan`
335
+ - `saw you might be interested in {{signal_topic}}, so hope this is relevant`
336
+ - `saw you in a few conversations around {{signal_topic}}, so hope this is relevant`
337
+ - `saw you in a few conversations about {{signal_topic}}, so may be off, but this seemed relevant`
338
+ - `may be off, but if {{workflow_signal}} is anywhere near your lane, this might be useful`
339
+ - `if {{workflow_signal}} is nowhere near your lane, ignore me`
340
+ - `figured this might matter if {{workflow_signal}} is live at {{company}}`
341
+ - `thought of {{company}} because {{observable_signal}} points at {{problem_context}}`
342
+ - `saw you raise your hand for {{signal_topic}}, so figured this was (hopefully) worth sending` only when the engagement signal is the actual source
343
+ - `saw you raise your hand for {{signal_topic}} (creepy to reach out based on that, i know) - but this felt too on the nose to ignore` only when the engagement signal is the actual source and the sender's voice can carry the cheekier aside
344
+
345
+ For LinkedIn-post-sourced campaigns (commenters, reactors, lead magnet
346
+ replies, or scraped conversations), it is acceptable to reference the
347
+ conversation when it explains why the note exists. Keep it topic-level, not
348
+ activity-log-level: `saw you in a few conversations around
349
+ {{signal_topic}}, so hope this is relevant` is acceptable; `saw you
350
+ commented on {{post_context}}` and `your LinkedIn activity around...` are
351
+ not.
352
+
353
+ Keep the apologetic nature, but aim it at uncertainty, not surveillance.
354
+ Good: `saw you in a few conversations about outbound, so may be off, but
355
+ this seemed relevant`, `may be off, but if outbound is anywhere near your
356
+ lane...`, `if this is nowhere near your outbound workflow, ignore me`, `hope
357
+ this is relevant if...`. Bad: `your role at {{company}} looked close...`,
358
+ because it asserts fit from a title and tells the buyer about themselves.
359
+
360
+ Block wordier source narration such as `you might not remember the thread,
361
+ but I found you through a {{signal_topic}} discussion and your
362
+ {{observable_role_context}} looked close to {{problem_context}}`. It reads
363
+ like sourcing metadata plus resume recap. Replace it with the shorter
364
+ topic-level bridge above, or omit the personalization line and start with
365
+ the buyer pain.
366
+
367
+ ### Personalization compression gate
368
+
369
+ Before a personalization line can survive into a template, rendered sample, or
370
+ Selected Winner, check it against these gates:
371
+
372
+ - **Bridge, not recap:** it must make why the note might matter feel earned. A
373
+ line that only says where the person worked, what role they held, or what
374
+ their company does is blocked.
375
+ - **Short by default:** target 6-14 words. A longer line must earn every word by
376
+ improving relevance or reducing assumption risk.
377
+ - **One inference only:** use one observed signal and one buyer-relevant bridge.
378
+ Do not stack two employers, two roles, and the product category into one line.
379
+ - **No product-centered bridge:** do not write `looked close to what [Product]
380
+ is built for`, `relevant to our platform`, or similar copy that centers the
381
+ sender's product before the buyer feels seen.
382
+ - **No title-fit assertion:** do not write `your [role] role at [company]
383
+ looked close to this problem`. A title/company can be the private reason you
384
+ selected the row, but the buyer-facing line should stay conditional:
385
+ `may be off, but if [workflow] is anywhere near your lane...`.
386
+ - **Swap test:** if another founder/operator could receive the line after only
387
+ changing names and companies, cut it or make the bridge more specific.
388
+ - **Tell-about-themselves test:** if the line merely reports a fact the buyer
389
+ already knows, rewrite it into a relevance hypothesis (`hope this is relevant
390
+ if...`) or omit it.
391
+
392
+ Blocked:
393
+
394
+ - `Your GTM and international growth work at Nas Daily and 1000media looked close to the kind of outbound work Sellable is built for.`
395
+ - `You might not remember the thread, but I found you through a LinkedIn outreach discussion and your sales development role at Gainsight looked close to this problem.`
396
+ - `Your enterprise sales role at Odoo looked close to this outbound campaign problem.`
397
+
398
+ Better:
399
+
400
+ - `hope this is relevant if market expansion is still on your plate.`
401
+ - `saw you in a few conversations around international growth, so hope this is relevant.`
402
+ - `saw you in a few conversations around LinkedIn outreach, so hope this is relevant.`
403
+ - `saw you in a few conversations about LinkedIn outreach, so may be off, but this seemed relevant.`
404
+ - `may be off, but if outbound is anywhere near your lane, this might be useful.`
405
+ - `figured this might matter if you're testing outbound by market.`
327
406
 
328
407
  ### Angle drafting & finalizer
329
408
 
@@ -1014,8 +1093,12 @@ defensive wording like `legit`, `real operation`, `not a side project`, or
1014
1093
  easy to delete.
1015
1094
 
1016
1095
  Do not use PS to explain why the pitch is credible, defend the message,
1017
- summarize the strategy, add a second offer, or patch a weak body. If the
1018
- PS sounds like internal reasoning, delete it.
1096
+ summarize the strategy, add a second offer, narrate the source thread, or patch
1097
+ a weak body. If the PS sounds like internal reasoning, delete it. Source
1098
+ disclaimers such as `p.s. if the source thread was just casual reading, ignore
1099
+ me` are BLOCKED; if the source is too weak to stand in the opener/body, omit it.
1100
+ A relevance-risk PS is allowed when it names uncertainty without narrating the
1101
+ source: `p.s. if this is nowhere near your outbound workflow, ignore me.`
1019
1102
 
1020
1103
  ### Raw proof translation test (HARD INVARIANT)
1021
1104
 
@@ -1154,8 +1237,9 @@ Before `confirmed`, run the selected winner against these gates:
1154
1237
  - **Non-assumption:** the opener does not assert what the buyer wants,
1155
1238
  feels, needs, or is trying to do unless the exact fact is grounded in
1156
1239
  the lead sample. If desire is inferred, use tentative framing like
1157
- `not sure if this is relevant, but...`, `thought this might be
1158
- relevant if...`, or `if you've ever wanted...`.
1240
+ `hope this is relevant if...`, `saw you might be interested in...`,
1241
+ `saw you in a few conversations around...`, `figured this might matter if...`,
1242
+ or `if you've ever wanted...`.
1159
1243
  - **Buyer-first opener:** after the greeting, the first substantive line
1160
1244
  should usually enter the buyer's world: a real signal, current-state
1161
1245
  pain, buyer-owned priority, or useful artifact. Sender-origin can come
@@ -1449,13 +1533,17 @@ infrastructure signal`, or `rails can match` unless that exact buyer
1449
1533
  urgency unless `lead-sample.json` states that exact fact. Phrases such
1450
1534
  as `clearly on your mind`, `obviously focused on`, `already thinking
1451
1535
  about`, or `clearly relevant` are BLOCKED. Source-y phrases such as
1452
- `saw you on...`, `saw you around...`, and `saw you engaging with...`
1536
+ `saw you on...`, bare `saw you around...`, and `saw you engaging with...`
1453
1537
  are also blocked unless the archived winner explicitly depends on that
1454
1538
  self-aware signal style. Translate the signal into low-certainty buyer
1455
- context instead: `you might not remember the thread, but I found you
1456
- through a [topic] discussion and your [observable role/company context]
1457
- looked close to [problem]`, `this may be too specific, but if [topic] is
1458
- part of what you're testing...`, or a similarly natural line.
1539
+ context instead: `hope this is relevant if [topic] is part of the plan`,
1540
+ `saw you might be interested in [topic], so hope this is relevant`, `saw you
1541
+ in a few conversations around [topic], so hope this is relevant`, `found you
1542
+ in a few conversations about [topic], so may be off, but this seemed
1543
+ relevant`, `figured this might matter if [workflow] is live at [company]`, or a similarly natural
1544
+ line. Longer source-recap forms such as `you might not remember the thread,
1545
+ but I found you through a [topic] discussion...` are BLOCKED; they narrate
1546
+ the scrape path instead of creating buyer relevance.
1459
1547
  - **Engagement reference is opt-in, not the default opener:** do not
1460
1548
  default to `{{first_name}}, saw you {{engagement_context}} on
1461
1549
  {{post_context}}`, `saw you reacted to...`, or equivalent retrieval-log
@@ -1505,6 +1593,11 @@ PO from your inbox?` beats `worth 15 min to compare notes?` because the
1505
1593
  commitment-lowering aside, concrete preview aside, proof-as-wink, or
1506
1594
  tight customer/result proof. If it explains the strategy, defends the
1507
1595
  pitch, or patches weak credibility, it is BLOCKED.
1596
+ PS source disclaimers are also BLOCKED: do not write `if the source thread
1597
+ was just casual reading, ignore me`, `only reaching out where the role and
1598
+ topic looked close`, or similar sourcing-defense copy.
1599
+ Relevance-risk opt-outs are allowed when they do not defend the source:
1600
+ `p.s. if this is nowhere near your outbound workflow, ignore me.`
1508
1601
  - **YC / backing PS:** a PS that only says `we're YC`, `we're YC W26`,
1509
1602
  `backed by YC`, or similar is BLOCKED as badge-flashing. If YC/backing
1510
1603
  is used, the same sentence must either tie to the buyer segment/outcome
@@ -1565,12 +1658,18 @@ LinkedIn UI already shows the recipient who sent the message (sender
1565
1658
  name, photo, headline), so the body should NEVER
1566
1659
  include `"X here"`, `"I'm Y"`, `"{{sender_name}}, {{title}} at
1567
1660
  {{company}}"`, or any self-identification phrase — those are
1568
- Filter-8 violations. NEVER references the recipient yet either (no
1569
- `{{first_name}} saw you...`, no `Your X is...`). Open with what
1570
- matters to the buyer or the operator-reality that led to it. Acceptable
1571
- openers:
1661
+ Filter-8 violations. Recipient context may lead only when it is a
1662
+ permissioned relevance bridge or self-aware engagement opener, not a resume
1663
+ recap, compliment, source citation, or `Your X is...` line. Open with what
1664
+ matters to the buyer, why this might be relevant, or the operator-reality that
1665
+ led to it. Acceptable openers:
1572
1666
 
1573
1667
  - `Hey {{first_name}}, [one plain sentence about what we built].`
1668
+ - `Hey {{first_name}}, hope this is relevant if [buyer context] is still on your plate.`
1669
+ - `Hey {{first_name}}, saw you might be interested in [topic], so hope this is relevant.`
1670
+ - `Hey {{first_name}}, saw you in a few conversations around [topic], so hope this is relevant.`
1671
+ - `Hey {{first_name}}, saw you raise your hand for [topic], so figured this was (hopefully) worth sending.`
1672
+ - `Hey {{first_name}}, saw you raise your hand for [topic] (creepy to reach out based on that, i know) - but this felt too on the nose to ignore.`
1574
1673
  - `Hey {{first_name}}, pre-[product], we [did the operator-reality
1575
1674
  thing] for [X] years; [one-line consequence].`
1576
1675
  - `Hey {{first_name}}, building a thing for [segment] I think you'd
@@ -1584,6 +1683,9 @@ Unacceptable Block-1 openers (Filter-8 violations):
1584
1683
  sent the message)
1585
1684
  - `Hey {{first_name}}, I'm {{sender_name}}, co-founder at [company].`
1586
1685
  - `{{sender_name}}, [title] at [company]. We do [X].`
1686
+ - `Hey {{first_name}}, caught your profile and thought...`
1687
+ - `Hey {{first_name}}, your GTM and international growth work at [Company A]
1688
+ and [Company B] looked close to what [Product] is built for.`
1587
1689
 
1588
1690
  **Default Block 2 — Mechanism.** ~1 sentence. What the product actually does
1589
1691
  in plain words. NOT a feature list. NOT a stack dump. NOT a
@@ -1804,10 +1906,14 @@ Rules:
1804
1906
  - if `lead-sample.json` carries **any** per-lead signal for this lead — a recent post, a recent hire, a visible tool in the headline, a topic engagement, a public initiative — the **message must reference it specifically**. Category-level copy is rejected.
1805
1907
  - default placement is **Block 3**, not Block 1. Keep Block 1 substance-first unless the archived motion clearly earns a signal-led opener without falling into source-citation / talk-at phrasing.
1806
1908
  - acceptable signal use by default:
1807
- - `"Not sure if this is relevant, but if [topic] is part of what you're testing, this may be useful."`
1808
- - `"Thought of {{company}} because [observable signal] touches a similar problem."`
1809
- - `"This may be too specific, but the [topic] angle felt close enough to send."`
1810
- - `"You might not remember the thread, but I found you through a [topic] discussion and your [observable role/company context] looked close to [problem]."`
1909
+ - `"Hope this is relevant if [topic] is part of the plan."`
1910
+ - `"Saw you might be interested in [topic], so hope this is relevant."`
1911
+ - `"Saw you in a few conversations around [topic], so hope this is relevant."`
1912
+ - `"Saw you in a few conversations about [topic], so may be off, but this seemed relevant."`
1913
+ - `"Thought of {{company}} because [observable signal] points at [problem]."`
1914
+ - `"Figured this might matter if [workflow] is live at {{company}}."`
1915
+ - `"Saw you raise your hand for [topic], so figured this was (hopefully) worth sending."`
1916
+ - `"Saw you raise your hand for [topic] (creepy to reach out based on that, i know) - but this felt too on the nose to ignore."`
1811
1917
  - blocked signal use:
1812
1918
  - `"AI-GTM stack is clearly on your mind."`
1813
1919
  - `"You're clearly focused on [area]."`
@@ -1816,13 +1922,20 @@ Rules:
1816
1922
  - `"Saw you on [topic]."`
1817
1923
  - `"Saw you around [topic]."`
1818
1924
  - `"Saw you engaging with [topic]."`
1819
- - signal-led opener shape is a **special case**, not the default. Use it only when the archived motion truly depends on it and the line can stay natural. Follow Superpower's `"saw you were active around some [topic] stuff recently and figured this might actually be relevant"` shape only when it reads like a real human note rather than a retrieval flex.
1925
+ - signal-led opener shape is a **special case**, not the default. Use it only when the archived motion truly depends on it and the line can stay natural. For LinkedIn-post-sourced campaigns, prefer `"saw you in a few conversations around [topic], so hope this is relevant"` when referencing the source makes the outreach feel less random. Avoid activity-log phrasing such as `"you commented on..."`, `"you reacted to..."`, or `"your LinkedIn activity..."` unless the approved motion is the deliberately self-aware raise-hand line.
1820
1926
  - tokenized engagement-source opener shape is BLOCKED by default:
1821
1927
  `{{first_name}}, saw you {{engagement_context}} on {{post_context}}` reads
1822
1928
  like surveillance unless the filled line is explicitly self-aware and
1823
- low-certainty. Prefer `you might not remember the thread, but I found you
1824
- through a [topic] discussion and your [observable role/company context] looked
1825
- close to [problem]` or omit the engagement reference entirely.
1929
+ low-certainty. Prefer a concise bridge such as `hope this is relevant if
1930
+ [topic] is part of the plan`, `saw you might be interested in [topic], so hope
1931
+ this is relevant`, `saw you in a few conversations around [topic], so hope this
1932
+ is relevant`, `saw you in a few conversations about [topic], so may be off,
1933
+ but this seemed relevant`, or one of the self-aware raise-hand shapes when the source is the
1934
+ actual reason for the note: `saw you raise your hand for [topic], so figured
1935
+ this was (hopefully) worth sending` or `saw you raise your hand for [topic]
1936
+ (creepy to reach out based on that, i know) - but this felt too on the nose to
1937
+ ignore`. Do not use the longer `you might not remember the thread...` shape;
1938
+ if the concise source bridge still feels awkward, omit the engagement reference.
1826
1939
  - do not describe the sender/client in third person inside the outbound message.
1827
1940
  `p.s. Saju's angle is...`, `Christian's angle is...`, `[sender]'s approach
1828
1941
  is...`, and similar lines are internal notes leaking into prospect copy. If the
@@ -1879,9 +1992,12 @@ A PS can do four jobs:
1879
1992
  must name what the customers used the product/service for, not just that
1880
1993
  they exist.
1881
1994
 
1882
- A PS must not explain strategy, defend the pitch, add a second unrelated
1883
- offer, or say the quiet part out loud. Lines like `this is not just a
1884
- platform idea` are blocked because they sound like internal rationale.
1995
+ A PS must not explain strategy, defend the pitch, narrate the source thread,
1996
+ add a second unrelated offer, or say the quiet part out loud. Lines like `this
1997
+ is not just a platform idea` and `if the source thread was just casual reading,
1998
+ ignore me` are blocked because they sound like internal rationale. A plain
1999
+ relevance-risk opt-out such as `if this is nowhere near your outbound workflow,
2000
+ ignore me` can stay when it lowers pressure without explaining the scrape.
1885
2001
 
1886
2002
  The reader does not know who the sender's colleagues are. Dropping a bare first name with no anchor reads like a resume dump that was cut in half.
1887
2003