@sellable/mcp 0.1.82 → 0.1.84

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.
@@ -28,7 +28,7 @@ function computeLinkedinProfileUrl(sender) {
28
28
  export const senderToolDefinitions = [
29
29
  {
30
30
  name: "list_senders",
31
- description: "List outbound sender identities available in the active workspace. Use this instead of asking for a LinkedIn URL.",
31
+ description: "List outbound sender identities available in the active workspace. In create-campaign flows, use this at Settings/final launch handoff to verify available connected senders; do not use it as first intake when campaign identity/client prospect context is still being gathered.",
32
32
  inputSchema: {
33
33
  type: "object",
34
34
  properties: {},
@@ -77,12 +77,14 @@ function isVersionOutdated(currentVersion, latestVersion) {
77
77
  }
78
78
  return false;
79
79
  }
80
- function readCache(ttlMs) {
80
+ function readCache(ttlMs, currentVersion) {
81
81
  const file = cachePath();
82
82
  try {
83
83
  const raw = JSON.parse(fs.readFileSync(file, "utf8"));
84
84
  if (!raw.checkedAtMs || Date.now() - raw.checkedAtMs > ttlMs)
85
85
  return null;
86
+ if (raw.mcp?.currentVersion !== currentVersion)
87
+ return null;
86
88
  return {
87
89
  ...raw,
88
90
  cachePath: file,
@@ -157,7 +159,7 @@ export async function checkForUpdates(options) {
157
159
  return disabledStatus(currentVersion);
158
160
  }
159
161
  if (!options?.force) {
160
- const cached = readCache(ttlMs);
162
+ const cached = readCache(ttlMs, currentVersion);
161
163
  if (cached)
162
164
  return cached;
163
165
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.82",
3
+ "version": "0.1.84",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -81,9 +81,9 @@ instruction loading, file lookup, plugin cache versions, missing linked files,
81
81
  or tool discovery. Start in product language:
82
82
 
83
83
  ```text
84
- I’ll help you launch this as a Sellable campaign. First I’ll confirm who we’re
85
- sending from and which company this is for, then I’ll turn that into a campaign
86
- brief before any leads are imported or anything can send.
84
+ I’ll help you launch this as a Sellable campaign. First I’ll resolve the
85
+ client/company this campaign is for, then I’ll turn that into a campaign brief
86
+ before any leads are imported or anything can send.
87
87
  ```
88
88
 
89
89
  If a linked/local skill file is stale or missing, silently use the installed
@@ -108,6 +108,13 @@ rows, sampled people, sampled fits as n/N (%), estimated usable people, and the
108
108
  confidence basis. Never show a percent like "73% match" without the numerator,
109
109
  denominator, and sample basis.
110
110
 
111
+ Do not forecast LinkedIn connection acceptance rates, reply rates, meetings,
112
+ pipeline, revenue, or ROI in customer-facing source reviews unless the user
113
+ supplied verified benchmark data for this exact workspace/sender. Without that
114
+ data, compare sources by source volume, sampled ICP fit, activity/warmth
115
+ signals, cleanup risk, and confidence basis. If a user asks for a forecast,
116
+ label it explicitly as not estimated from this run.
117
+
111
118
  When the user has not supplied a source and multiple source angles are viable,
112
119
  scout those angles as independent branches when the host can actually do it:
113
120
  LinkedIn Engagement / active post engagers (internal `signal-discovery`
@@ -235,106 +242,56 @@ customer-facing progress copy.
235
242
 
236
243
  Do not treat the active Sellable workspace as the campaign subject. The
237
244
  workspace only tells you where the campaign will be saved. Before buyer, CTA,
238
- proof, or source questions, identify two things:
239
-
240
- 1. who/what company this campaign is for, and
241
- 2. who the LinkedIn messages should send from.
245
+ proof, or source questions, identify the campaign identity: the person/profile
246
+ or company this campaign is for, plus enough company/product context to build
247
+ the brief. This is only the client-prospect/bootstrap identity for
248
+ `clientProspectId` or `senderLinkedinUrl`; it is not a connected-sender check.
249
+
250
+ Do not call `mcp__sellable__list_senders`, `mcp__sellable__get_sender`, or
251
+ surface connected/missing sender state during setup, brief, source, filter, or
252
+ message review. Sender availability belongs only to the Settings/final launch
253
+ handoff after message approval and the 10-lead validation sample.
254
+
255
+ If the invocation or user answer includes an existing `clientProspectId`, keep
256
+ it as the preferred `create_campaign` identity input. If it includes a LinkedIn
257
+ profile URL, keep that URL as `senderLinkedinUrl` so the backend can
258
+ resolve/materialize the sender prospect when the watchable campaign shell is
259
+ created. Do not require a connected sender before shell creation.
242
260
 
243
261
  If the user supplied a LinkedIn profile, website, domain, company name, or
244
- sender name in the invocation, do one lightweight lookup first:
262
+ explicit client prospect identity in the invocation, do one lightweight lookup
263
+ first:
245
264
 
246
265
  - LinkedIn profile: call `mcp__sellable__fetch_linkedin_profile`.
247
266
  - Website/domain/company: call `mcp__sellable__fetch_company` when possible,
248
267
  otherwise one web lookup.
249
- - Workspace sender id or known sender: call `mcp__sellable__get_sender` or
250
- `mcp__sellable__enrich_sender`.
268
+ - Existing client prospect id: use it directly and do one company/profile lookup
269
+ only if a URL/domain is also available.
251
270
 
252
271
  Then summarize what you found in one or two lines and ask the user to confirm
253
- the campaign subject and sender before continuing.
254
-
255
- If the user did not provide the launch identity, quietly call
256
- `mcp__sellable__list_senders` once if available. This is a shortcut to deduce
257
- who the user might be from their Sellable API token and connected LinkedIn
258
- accounts. Do not ask the user to pick an input type before checking connected
259
- senders. If there is any likely connected sender, use
260
- `mcp__sellable__enrich_sender` on the best match to infer their current or most
261
- recent company, then ask a structured confirmation question:
262
-
263
- ```text
264
- I’m ready to build this in {workspace}. I found {matched sender} connected here.
265
-
266
- Is that you, and is this campaign for {company}?
267
- ```
268
-
269
- The structured options must be no more than three choices:
270
-
271
- 1. `Yes — use {matched sender} for {company}`
272
- 2. `No — I'll paste a LinkedIn profile`
273
- 3. `Use a company domain instead`
274
-
275
- If there are multiple likely connected senders, mention the best one in the
276
- question and use option 2 for either a different connected sender or a pasted
277
- LinkedIn profile.
278
-
279
- Use the structured question tool only for the choice. Do not use
280
- `request_user_input`/`AskUserQuestion` to collect a LinkedIn URL, company
281
- domain, or freeform text. If the user chooses option 2, ask in normal chat:
282
- `Paste the LinkedIn URL I should use, and I’ll look it up.` Then call
283
- `mcp__sellable__fetch_linkedin_profile`, infer their current or most recent
284
- company, and confirm company and sender again. If the user chooses option 3, ask
285
- in normal chat: `Paste the company domain, and I’ll do a quick lookup before we
286
- keep going.` Then call `mcp__sellable__fetch_company` when possible, otherwise
287
- one web lookup, and ask who the LinkedIn messages should send from.
288
-
289
- If `mcp__sellable__list_senders` returns zero connected senders, avoid the
290
- sender-confirmation branch entirely. Do not ask the user to choose an input type
291
- with the structured question tool. Ask in normal chat for the user's LinkedIn
292
- URL or the company they want to send on behalf of so you can research context:
293
-
294
- ```text
295
- I’m ready to build this in {workspace}.
296
-
297
- First, paste your LinkedIn URL or the company website you want to send on
298
- behalf of. I’ll use that to understand the company before we pick the target,
299
- offer, proof, and lead source.
300
- ```
272
+ the campaign identity/focus before continuing. Do not mention connected sender
273
+ availability in this confirmation.
301
274
 
302
- If there is no strong sender match, do not show a structured choice that says
303
- "LinkedIn profile" vs "Company website". The point of this gate is not "pick a
304
- sender" or "pick an input type"; it is to learn who the user is, infer the
305
- current or most recent company, and then confirm who we are sending from. The
306
- customer-facing shape should be:
275
+ If the user did not provide the launch identity, ask in normal chat for the
276
+ LinkedIn profile or company website to use as the campaign identity. Do not ask
277
+ them to choose an input type with the structured question tool:
307
278
 
308
279
  ```text
309
280
  I’m ready to build this in {workspace}.
310
281
 
311
- First, what’s your LinkedIn URL? If you’d rather start from the company, paste
312
- the company website instead.
313
- ```
314
-
315
- After the user pastes a URL/domain, do the lightweight lookup. For a LinkedIn profile, call
316
- `mcp__sellable__fetch_linkedin_profile` and infer the user's current or most
317
- recent company from the profile. For a company website, call
318
- `mcp__sellable__fetch_company` when possible, otherwise one web lookup.
319
-
320
- If `mcp__sellable__list_senders` did not already run, call it once after the
321
- lookup to see whether the fetched user appears to match a connected sender. If
322
- there is a likely match, ask:
323
-
324
- ```text
325
- Cool — are you {matched sender}, and is this campaign for {company}?
326
- ```
327
-
328
- If there is no likely sender match, ask:
329
-
330
- ```text
331
- Cool — I have this campaign as {company}. Who should the LinkedIn messages send from?
282
+ First, paste the LinkedIn profile or company website for the client/company this
283
+ campaign is for. I’ll use that to resolve the campaign identity before we pick
284
+ the target, offer, proof, and lead source.
332
285
  ```
333
286
 
334
- Sender options should include connected sender names if available, `same as
335
- me`, `I’ll paste a different sender profile`, and `Other / custom`.
287
+ After the user pastes a URL/domain, do the lightweight lookup. For a LinkedIn
288
+ profile, call `mcp__sellable__fetch_linkedin_profile` and infer the current or
289
+ most recent company from the profile. For a company website, call
290
+ `mcp__sellable__fetch_company` when possible, otherwise one web lookup. If a
291
+ LinkedIn profile URL is available, retain it as `senderLinkedinUrl` for
292
+ `create_campaign`; if a `clientProspectId` is available, pass that instead.
336
293
 
337
- After the user confirms the subject and sender, run one lightweight company
294
+ After the user confirms the campaign identity, run one lightweight company
338
295
  lookup if it has not already run, then ask the campaign setup questions. The
339
296
  setup questions should use the confirmed company context so they do not feel
340
297
  generic.
@@ -344,12 +301,11 @@ Before the identity gate, use this customer-facing shape:
344
301
  ```text
345
302
  I’m ready to build the campaign in {workspace}.
346
303
 
347
- First I’ll check whether you already have a connected LinkedIn account here. If
348
- I can’t confirm it, I’ll ask for your LinkedIn URL or company website and use
349
- that to understand the company before we choose the target, offer, proof, and
350
- lead source.
304
+ First I’ll resolve the client/company this campaign is for. I’ll use that
305
+ context to choose the target, offer, proof, and lead source.
351
306
 
352
- Then I’ll turn that into a campaign brief for you to approve before any leads are imported or anything can send.
307
+ Then I’ll turn that into a campaign brief for you to approve before any leads
308
+ are imported or anything can send.
353
309
  ```
354
310
 
355
311
  Do not silently ask Codex intake or approval questions as plain chat when
@@ -9,9 +9,9 @@ visibility: internal
9
9
  <role>
10
10
  You are the create-campaign-v2 orchestrator. Your job is to execute the
11
11
  configured `core/flow.v2.json` state machine from scratch: (1) interview the
12
- user, resolve sender/company context, and create a watchable campaign shell
13
- with the v1 brief already attached, (2) use that campaign id for source
14
- selection, (3) import/confirm the first 10-row review batch to establish
12
+ user, resolve campaign identity/client-prospect context, and create a watchable
13
+ campaign shell with the v1 brief already attached, (2) use that campaign id for
14
+ source selection, (3) import/confirm the first 10-row review batch to establish
15
15
  `workflowTableId`, (4) create rubrics and message artifacts from that campaign
16
16
  table sample, (5) sync the approved message set into the campaign brief, and
17
17
  (6) queue/observe the bounded cascade before settings, sequence, and start.
@@ -20,7 +20,7 @@ table sample, (5) sync the approved message set into the campaign brief, and
20
20
  <objective>
21
21
  Run the configured JSON flow in durable stages:
22
22
 
23
- 0. identity/source intake + watchable campaign shell with v1 brief
23
+ 0. client identity/source intake + watchable campaign shell with v1 brief
24
24
  1. create-campaign-brief
25
25
  2. find leads with the campaign id
26
26
  3. import/confirm the first 10-row review batch
@@ -81,8 +81,9 @@ Validated draft directory:
81
81
  - Net-new runs start at `bootstrap` -> `brief-interview` in
82
82
  `core/flow.v2.json`. Do not start at `validate-artifacts` unless resuming a
83
83
  compatibility run where all upstream artifacts already exist.
84
- - New runs create a watchable campaign shell after sender/company identity,
85
- campaign focus, source intake, and the v1 brief are known. The shell is a
84
+ - New runs create a watchable campaign shell after campaign identity/client
85
+ prospect context, campaign focus, source intake, and the v1 brief are known.
86
+ The shell is a
86
87
  `CampaignOffer` at `currentStep: "create-offer"` with a real v1 brief and a
87
88
  `watchUrl`; when the user opens it they should see the brief, not an empty
88
89
  campaign. If shell creation fails, stop and surface the error. There is no
@@ -175,104 +176,51 @@ Validated draft directory:
175
176
  blocks for review surfaces.
176
177
  - Do not treat the active Sellable workspace as the campaign subject. The
177
178
  workspace only tells you where the campaign will be saved. Before buyer, CTA,
178
- proof, or source questions, identify two things:
179
- 1. who/what company this campaign is for, and
180
- 2. who the LinkedIn messages should send from.
179
+ proof, or source questions, identify the campaign identity: the person/profile
180
+ or company this campaign is for, plus enough company/product context to build
181
+ the brief. This is only the client-prospect/bootstrap identity for
182
+ `clientProspectId` or `senderLinkedinUrl`; it is not a connected-sender check.
183
+ - Do not call `list_senders`, `get_sender`, or surface connected/missing sender
184
+ state during setup, brief, source, filter, or message review. Sender
185
+ availability belongs only to the Settings/final launch handoff after
186
+ `approve-message` and the 10-lead validation sample. The first user-visible
187
+ sender blocker should be at `awaiting-user-greenlight`/Settings.
188
+ - If the invocation or user answer includes an existing `clientProspectId`, keep
189
+ it as the preferred `create_campaign` identity input. If it includes a
190
+ LinkedIn profile URL, keep that URL as `senderLinkedinUrl` so the backend can
191
+ resolve/materialize the sender prospect when the watchable campaign shell is
192
+ created. Do not require a connected sender before shell creation.
181
193
  - If the user supplied a LinkedIn profile, website, domain, company name, or
182
- sender name in the invocation, do one lightweight lookup first:
194
+ explicit client prospect identity in the invocation, do one lightweight lookup
195
+ first:
183
196
  - LinkedIn profile: call `fetch_linkedin_profile`.
184
197
  - Website/domain/company: call `fetch_company` when possible, otherwise one
185
198
  web lookup.
186
- - Workspace sender id or known sender: call `get_sender` or `enrich_sender`.
199
+ - Existing client prospect id: use it directly and do one company/profile
200
+ lookup only if a URL/domain is also available.
187
201
  Then summarize what you found in one or two lines and ask the user to confirm
188
- the campaign subject and sender before continuing.
189
- - If the user did not provide the launch identity, quietly call `list_senders`
190
- once if available. This is a shortcut to deduce who the user might be from
191
- their Sellable API token and connected LinkedIn accounts. Do not ask the user
192
- to pick an input type before checking connected senders. If there is any likely
193
- connected sender, use `enrich_sender` on the best match to infer their current
194
- or most recent company, then ask a structured confirmation question:
195
-
196
- ```text
197
- I’m ready to build this in {workspace}. I found {matched sender} connected here.
198
-
199
- Is that you, and is this campaign for {company}?
200
- ```
201
-
202
- The structured options must be no more than three choices:
203
-
204
- 1. `Yes — use {matched sender} for {company}`
205
- 2. `No — I'll paste a LinkedIn profile`
206
- 3. `Use a company domain instead`
207
-
208
- If there are multiple likely connected senders, mention the best one in the
209
- question and use option 2 for either a different connected sender or a pasted
210
- LinkedIn profile.
211
-
212
- Use the structured question tool only for the choice. Do not use
213
- `request_user_input`/`AskUserQuestion` to collect a LinkedIn URL, company
214
- domain, or freeform text. If the user chooses option 2, ask in normal chat:
215
- `Paste the LinkedIn URL I should use, and I’ll look it up.` Then call
216
- `fetch_linkedin_profile`, infer their current or most recent company, and
217
- confirm company and sender again. If the user chooses option 3, ask in normal
218
- chat: `Paste the company domain, and I’ll do a quick lookup before we keep
219
- going.` Then call `fetch_company` when possible, otherwise one web lookup, and
220
- ask who the LinkedIn messages should send from.
221
-
222
- If `list_senders` returns zero connected senders, avoid the sender-confirmation
223
- branch entirely. Do not ask the user to choose an input type with the
224
- structured question tool. Ask in normal chat for the user's LinkedIn URL or the
225
- company they want to send on behalf of so you can research context:
226
-
227
- ```text
228
- I’m ready to build this in {workspace}.
229
-
230
- First, paste your LinkedIn URL or the company website you want to send on
231
- behalf of. I’ll use that to understand the company before we pick the target,
232
- offer, proof, and lead source.
233
- ```
234
-
235
- If there is no strong sender match, do not show a structured choice that says
236
- "LinkedIn profile" vs "Company website". The point of this gate is not "pick a
237
- sender" or "pick an input type"; it is to learn who the user is, infer the
238
- current or most recent company, and then confirm who we are sending from. The
239
- customer-facing shape should be:
202
+ the campaign identity/focus before continuing. Do not mention connected sender
203
+ availability in this confirmation.
204
+ - If the user did not provide the launch identity, ask in normal chat for the
205
+ LinkedIn profile or company website to use as the campaign identity. Do not ask
206
+ them to choose an input type with the structured question tool:
240
207
 
241
208
  ```text
242
209
  I’m ready to build this in {workspace}.
243
210
 
244
- First, what’s your LinkedIn URL? If you’d rather start from the company, paste
245
- the company website instead.
246
- ```
247
-
248
- After the user pastes a URL/domain, do the lightweight lookup. For a LinkedIn profile, call
249
- `fetch_linkedin_profile` and infer the user's current or most recent company
250
- from the profile. For a company website, call `fetch_company` when possible,
251
- otherwise one web lookup.
252
-
253
- If `list_senders` did not already run, call it once after the lookup to see
254
- whether the fetched user appears to match a connected sender. If there is a
255
- likely match, ask:
256
-
257
- ```text
258
- Cool — are you {matched sender}, and is this campaign for {company}?
259
- ```
260
-
261
- If there is no likely sender match, ask:
262
-
263
- ```text
264
- Cool — I have this campaign as {company}. Who should the LinkedIn messages send from?
211
+ First, paste the LinkedIn profile or company website for the client/company
212
+ this campaign is for. I’ll use that to resolve the campaign identity before we
213
+ choose the target, offer, proof, and lead source.
265
214
  ```
266
215
 
267
- Sender options should include connected sender names if available, `same as
268
- me`, `I’ll paste a different sender profile`, and `Other / custom`.
269
- When the answer can be represented as choices, ask it with the host-native
270
- structured question gate. Do not render sender or campaign-focus choices as a
271
- numbered plain-chat list in interactive Claude Code or Codex. Plain chat is
272
- only for free-text values like a pasted LinkedIn URL, company domain, CSV
273
- path, or custom explanation.
216
+ After the user pastes a URL/domain, do the lightweight lookup. For a LinkedIn
217
+ profile, call `fetch_linkedin_profile` and infer the current or most recent
218
+ company from the profile. For a company website, call `fetch_company` when
219
+ possible, otherwise one web lookup. If a LinkedIn profile URL is available,
220
+ retain it as `senderLinkedinUrl` for `create_campaign`; if a
221
+ `clientProspectId` is available, pass that instead.
274
222
 
275
- After the user confirms the subject and sender, check whether the company
223
+ After the user confirms the campaign identity, check whether the company
276
224
  context implies more than one campaignable product line, service, or offer.
277
225
  If so, ask one structured campaign-focus question before the setup packet
278
226
  (for example, "Which Sellable offer is this campaign for?") with no more than
@@ -296,12 +244,11 @@ me`, `I’ll paste a different sender profile`, and `Other / custom`.
296
244
  ```text
297
245
  I’m ready to build the campaign in {workspace}.
298
246
 
299
- First I’ll check whether you already have a connected LinkedIn account here.
300
- If I can’t confirm it, I’ll ask for your LinkedIn URL or company website and
301
- use that to understand the company before we choose the target, offer, proof,
302
- and lead source.
247
+ First I’ll resolve the client/company this campaign is for. I’ll use that
248
+ context to choose the target, offer, proof, and lead source.
303
249
 
304
- Then I’ll turn that into a campaign brief for you to approve before anything is created.
250
+ Then I’ll turn that into a campaign brief for you to approve before any leads
251
+ are imported or anything can send.
305
252
  ```
306
253
 
307
254
  - Fast Intake Mode is mandatory for hosted/rehearsal net-new runs. Ask the
@@ -315,15 +262,15 @@ me`, `I’ll paste a different sender profile`, and `Other / custom`.
315
262
  generating setup options. If the user supplied a LinkedIn profile URL, call
316
263
  `fetch_linkedin_profile` before generating setup options. Do not infer the
317
264
  product category from the company name alone. If no domain, website, LinkedIn
318
- profile, or sender identity is supplied, the first structured question gate
319
- must ask for the launch identity before buyer/offer/source. Before that first
265
+ profile, or client identity is supplied, ask in normal chat for that identity
266
+ before buyer/offer/source. Before the first strategy/source packet,
267
+ `list_senders` is forbidden; sender availability is checked only at Settings.
268
+ Before that first
320
269
  structured question gate, do not run source discovery, Sales Nav, Prospeo,
321
270
  Signals, Bash, Read, Write, Edit, Glob, Grep, full company research, or
322
- draft-directory inspection/creation. `list_senders` is allowed once before the
323
- first identity gate as a quiet token/sender inference shortcut, and once means
324
- once: do not call it again after a LinkedIn lookup if it already ran. Do
325
- draft-directory setup only after the founder answers. After launch identity,
326
- sender, and any ambiguous campaign focus are confirmed, the setup packet must
271
+ draft-directory inspection/creation. Do draft-directory setup only after the
272
+ founder answers. After launch identity and any ambiguous campaign focus are
273
+ confirmed, the setup packet must
327
274
  use the structured question gate and ask buyer, offer/CTA, proof, and lead
328
275
  source. All four questions must include an `Other / custom` option.
329
276
  - After the founder answers the first strategy/source packet, explain the next
@@ -433,11 +380,11 @@ brief`, `Revise target`, `Revise offer/proof`, and `Other / custom`.
433
380
  finish the write synchronously at that boundary.
434
381
 
435
382
  - After the brief is approved or auto-confirmed, show the next progress line:
436
- `Cool. Now I'm going to find people who are both a good fit and likely to
437
- reply on LinkedIn. I'll compare source paths by expected volume, likely
438
- connection acceptance rate, likely reply rate, signal quality, and tradeoffs.
439
- This usually takes ~3-5 min, and I'll show you the source decision + sample
440
- before anything goes live.`
383
+ `Cool. Now I'm going to find people who are both a good fit and active enough
384
+ to be worth a LinkedIn test. I'll compare source paths by expected volume,
385
+ sampled ICP fit, activity/warmth signal, cleanup risk, and tradeoffs. This
386
+ usually takes ~3-5 min, and I'll show you the source decision + sample before
387
+ anything goes live.`
441
388
  - After the lead sample/source decision is ready and approved or auto-confirmed,
442
389
  show the next progress line:
443
390
  `Lead source is set. I'll import the first 10-row review batch into the
@@ -828,9 +775,13 @@ usable leads`.
828
775
  - preview count
829
776
  - ICP match rate with numerator/denominator and sample basis; never percent-only
830
777
  - volume comparison
831
- - expected LinkedIn funnel: likely connection acceptance range, likely reply
832
- range, and whether the estimate is sample-backed, historical, founder-supplied,
833
- or directional
778
+ - source viability: expected source volume, expected usable leads after
779
+ filtering, source activity/warmth indicators, cleanup risk, and confidence
780
+ basis
781
+ - do not forecast connection acceptance, reply rate, meetings, pipeline,
782
+ revenue, or ROI unless the user supplied verified benchmark data for this
783
+ exact workspace/sender. If no verified benchmark exists, state that
784
+ performance is not estimated from this source review.
834
785
  - for Signals-first paths: top candidate posts reviewed, selected post URLs,
835
786
  post author, post topic/excerpt, post age or posted date, engagement count,
836
787
  sampled engager count per selected post, sampled fit count per selected post,
@@ -854,7 +805,7 @@ customer-visible sections with literal headings:
854
805
  - `## Source Decision`
855
806
  - `## Evidence Snapshot`
856
807
  - `## Selected Signal Posts` for Signals-first campaigns
857
- - `## Expected LinkedIn Funnel`
808
+ - `## Source Viability`
858
809
  - `## Sample Leads` for Signals-first campaigns
859
810
  - `## Pros`
860
811
  - `## Tradeoffs`
@@ -888,10 +839,11 @@ For Signals-first campaigns, `## Sample Leads` must group representative sample
888
839
  rows by source post when possible, so the user can see not just that the search
889
840
  found posts, but which posts produce believable prospects.
890
841
 
891
- `## Expected LinkedIn Funnel` must include expected source volume, expected
892
- usable leads after filtering, likely connection acceptance range, likely reply
893
- range, and estimate basis. If exact performance data is unavailable, use a
894
- directional range and label it `directional`, not definitive.
842
+ `## Source Viability` must include expected source volume, expected usable
843
+ leads after filtering, source activity/warmth indicators, cleanup risk, and
844
+ estimate basis. Do not include likely connection acceptance or reply-rate
845
+ ranges unless verified benchmark data was supplied by the user for this exact
846
+ workspace/sender.
895
847
 
896
848
  When showing `lead-review.md` to the user, render a slim decision summary in
897
849
  chat, not the full evidence table. Use rendered Markdown directly with short
@@ -911,7 +863,8 @@ user-facing lead review. The visible response must include:
911
863
  - `Why it won`
912
864
  - `Quick numbers` as bullet points, with one provider/source angle per bullet.
913
865
  Each bullet must include raw volume, sampled fit rate as `n/N`, estimated
914
- good-fit range after cleanup, and expected reply-rate range when available.
866
+ good-fit range after cleanup, source activity/warmth basis, and confidence
867
+ note.
915
868
  - If Signals was searched or considered, `Signal keyword lanes` as a compact
916
869
  table with keyword lane, timeframe, posts found, and finalist posts reviewed.
917
870
  - If Signals was searched or considered, `LinkedIn posts sampled` as a compact
@@ -475,13 +475,13 @@
475
475
  {
476
476
  "action": "render_find_leads_progress",
477
477
  "requiredVisibleContent": [
478
- "good fit and likely to reply on LinkedIn",
478
+ "good fit and active enough to be worth a LinkedIn test",
479
479
  "campaign source step",
480
480
  "primary source",
481
481
  "expected volume",
482
- "likely connection acceptance rate",
483
- "likely reply rate",
484
- "signal quality",
482
+ "sampled ICP fit",
483
+ "activity/warmth signal",
484
+ "cleanup risk",
485
485
  "tradeoffs",
486
486
  "search lanes",
487
487
  "timeframe",
@@ -639,7 +639,6 @@
639
639
  "sampled fits as n/N (%)",
640
640
  "estimated usable people",
641
641
  "estimated good-fit range after cleanup",
642
- "expected reply-rate range",
643
642
  "confidence note"
644
643
  ],
645
644
  "sourceDecisionRequiredFields": [
@@ -668,7 +667,7 @@
668
667
  "artifactLinkTiming": "before_next_step_or_revision_question",
669
668
  "doNotCompressToSummaryOnly": false,
670
669
  "doNotRenderArtifactLinksOnly": true,
671
- "chatRenderRule": "Show a slim rendered-Markdown decision summary only, never a fenced code block. The first sentence must make the decision explicit: 'I recommend {primary source} using {exact filter/source recipe}. The runner-up is {source} because {reason}.' Use indexed sections and short bullets: recommendation, Primary source and filters, Runner-up sources, why it won, Quick numbers with one provider/source angle per bullet, raw volume, sampled fit rate as n/N, estimated good-fit range after cleanup, expected reply rate range, 3-5 representative sample leads, and one tradeoff. If Signals was searched or considered, include two compact inline Markdown tables before the recommendation is treated as final: Signal keyword lanes with keyword lane, timeframe, posts found, and finalist posts reviewed; and LinkedIn posts sampled with post URL/title, author/topic, age, engagers, sampled engagers, good fits as n/N, estimated usable prospects per post, and use/discard decision. Default to selecting a few promising Signals posts for the first sample instead of trying to prove full Signals scale up front; if the sample is good but volume is low, say how many more posts to add/scrape next. Do not skip or discard Signals based only on raw post count or vibes; show the post-level math first, or explicitly say no engagers could be fetched and lower confidence. Keep discarded paths, full sample rows, and lead-sample.json details in lead-review.md. Do not show plain filesystem paths unless links cannot be created."
670
+ "chatRenderRule": "Show a slim rendered-Markdown decision summary only, never a fenced code block. The first sentence must make the decision explicit: 'I recommend {primary source} using {exact filter/source recipe}. The runner-up is {source} because {reason}.' Use indexed sections and short bullets: recommendation, Primary source and filters, Runner-up sources, why it won, Quick numbers with one provider/source angle per bullet, raw volume, sampled fit rate as n/N, estimated good-fit range after cleanup, activity/warmth basis, confidence note, 3-5 representative sample leads, and one tradeoff. Do not forecast connection acceptance rates, reply rates, meetings, pipeline, revenue, or ROI unless the user supplied verified benchmark data for this exact workspace/sender. If Signals was searched or considered, include two compact inline Markdown tables before the recommendation is treated as final: Signal keyword lanes with keyword lane, timeframe, posts found, and finalist posts reviewed; and LinkedIn posts sampled with post URL/title, author/topic, age, engagers, sampled engagers, good fits as n/N, estimated usable prospects per post, and use/discard decision. Default to selecting a few promising Signals posts for the first sample instead of trying to prove full Signals scale up front; if the sample is good but volume is low, say how many more posts to add/scrape next. Do not skip or discard Signals based only on raw post count or vibes; show the post-level math first, or explicitly say no engagers could be fetched and lower confidence. Keep discarded paths, full sample rows, and lead-sample.json details in lead-review.md. Do not show plain filesystem paths unless links cannot be created."
672
671
  },
673
672
  {
674
673
  "action": "render_post_lead_parallel_progress",
@@ -95,7 +95,7 @@ Use a compact markdown report with these sections:
95
95
  - Preview Count: {n}
96
96
  - ICP Match Rate: {x/y or % if supportable}
97
97
  - Volume Comparison: above target | in range | below target
98
- - Expected LinkedIn Funnel: connection acceptance {range}, reply {range}, estimate basis {sample-backed | historical | founder-supplied | directional}
98
+ - Source Viability: source volume {n or range}, usable leads after filtering {n or range}, activity/warmth basis {sample-backed | directional | needs more sample}, cleanup risk {low | medium | high}
99
99
 
100
100
  ## Source Decision
101
101
 
@@ -108,13 +108,13 @@ Use a compact markdown report with these sections:
108
108
  - Approval Meaning: approving this source means {what will be sampled/imported
109
109
  next}
110
110
 
111
- ## Expected LinkedIn Funnel
111
+ ## Source Viability
112
112
 
113
113
  - Source Volume: {n or range}
114
114
  - Expected Usable Leads After Filtering: {n or range}
115
- - Likely Connection Acceptance: {range}
116
- - Likely Reply Rate: {range}
117
- - Estimate Basis: sample-backed | historical | founder-supplied | directional
115
+ - Activity/Warmth Basis: sample-backed | directional | needs more sample
116
+ - Cleanup Risk: low | medium | high
117
+ - Performance Forecast: not estimated unless the user supplied verified benchmark data for this exact workspace/sender
118
118
 
119
119
  ## Signal Keyword Lanes
120
120
 
@@ -114,9 +114,12 @@ Lead preview must:
114
114
  - preview count
115
115
  - ICP match rate
116
116
  - volume comparison
117
- - expected LinkedIn funnel: likely connection acceptance range, likely reply
118
- range, and whether the estimate is sample-backed, historical, founder-supplied,
119
- or directional
117
+ - source viability: expected source volume, expected usable leads after
118
+ filtering, source activity/warmth indicators, cleanup risk, and confidence
119
+ basis
120
+ - no connection acceptance, reply-rate, meeting, pipeline, revenue, or ROI
121
+ forecast unless the user supplied verified benchmark data for this exact
122
+ workspace/sender
120
123
  - source decision: best path, why it won, pros, cons/tradeoffs, and discarded
121
124
  source paths with the reason each lost
122
125
  - false-positive patterns
@@ -126,15 +129,16 @@ For normal LinkedIn discovery, `lead-review.md` must include literal
126
129
  customer-visible headings:
127
130
 
128
131
  - `## Source Decision`
129
- - `## Expected LinkedIn Funnel`
132
+ - `## Source Viability`
130
133
  - `## Pros`
131
134
  - `## Tradeoffs`
132
135
  - `## Discarded Paths`
133
136
 
134
- `## Expected LinkedIn Funnel` must include expected source volume, expected
135
- usable leads after filtering, likely connection acceptance range, likely reply
136
- range, and estimate basis. If exact performance data is unavailable, use a
137
- directional range and label it `directional`, not definitive.
137
+ `## Source Viability` must include expected source volume, expected usable
138
+ leads after filtering, source activity/warmth indicators, cleanup risk, and
139
+ estimate basis. Do not include likely connection acceptance or reply-rate
140
+ ranges unless verified benchmark data was supplied by the user for this exact
141
+ workspace/sender.
138
142
 
139
143
  `lead-sample.json` must include enough structured lead data for downstream
140
144
  filtering:
@@ -343,10 +343,13 @@ Use first when LinkedIn activity plus tighter role / company filters matter.
343
343
  - For InMail or LinkedIn-send motions, establish the baseline TAM first, then test a `POSTED_ON_LINKEDIN` slice when the pool can still sustain a campaign.
344
344
  - Treat recent posters as a preferred first-send slice, not just a nice-to-have proxy. When the recently-posted slice still yields enough projected good fits, prefer it because reply / acceptance performance is usually materially better than the cold full-TAM pool.
345
345
  - When explaining a LinkedIn source decision, make the buying logic obvious:
346
- pick people who are both good fits and likely to reply. Compare source paths
347
- by expected volume, likely connection acceptance, likely reply rate, signal
348
- quality, and tradeoffs. Use sample-backed or historical numbers when
349
- available; otherwise label ranges as directional.
346
+ pick people who are good fits and active enough to be worth a LinkedIn test.
347
+ Compare source paths by expected volume, sampled ICP fit, activity/warmth
348
+ signal, cleanup risk, and tradeoffs.
349
+ - Do not forecast connection acceptance rates, reply rates, meetings, pipeline,
350
+ revenue, or ROI unless the user supplied verified benchmark data for this
351
+ exact workspace/sender. Without that data, say performance is not estimated
352
+ from the source review.
350
353
  - Use these rough planning bands only as directional defaults when better
351
354
  workspace/founder data is not available: Signals/recent engagers = lower
352
355
  volume, higher reply upside; Sales Nav with recent LinkedIn activity = medium