@sellable/mcp 0.1.83 → 0.1.85
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.
- package/dist/tools/campaigns.js +5 -5
- package/dist/tools/flow-preflight.js +4 -4
- package/dist/update-check.js +4 -2
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +7 -0
- package/skills/create-campaign-v2/SKILL.md +40 -24
- package/skills/create-campaign-v2/core/flow.v2.json +8 -14
- package/skills/create-campaign-v2/references/lead-validation-preview.md +5 -5
- package/skills/create-campaign-v2/references/validation-criteria.md +12 -8
- package/skills/find-leads/SKILL.md +7 -4
package/dist/tools/campaigns.js
CHANGED
|
@@ -124,8 +124,8 @@ export const campaignToolDefinitions = [
|
|
|
124
124
|
{
|
|
125
125
|
name: "create_campaign",
|
|
126
126
|
description: 'Create a new campaign offer OR resume an existing one. Low-level write tool: load create-campaign workflow instructions first via get_subskill_prompt({ subskillName: "create-campaign" }) (or bootstrap_create_campaign + nextStep). If campaignId is provided, this tool returns the watchUrl + state for that campaign instead of creating a new campaign.\n\n' +
|
|
127
|
-
"INPUTS:\n- Pass either `clientProspectId` (preferred) or `senderLinkedinUrl` for net-new campaigns.\n- `clientProspectId` is the EnrichedProspect row ID for the campaign
|
|
128
|
-
"PREREQUISITES:\n- If you provide `senderLinkedinUrl`, it is used as a
|
|
127
|
+
"INPUTS:\n- Pass either `clientProspectId` (preferred) or `senderLinkedinUrl` for net-new campaigns.\n- `clientProspectId` is the EnrichedProspect row ID for the campaign identity/client prospect, used by ICP scoring, message generation, and brief rendering.\n- `senderLinkedinUrl` may be passed when `clientProspectId` is not yet materialized; the backend will attempt to resolve a campaign identity prospect from it.\n\n" +
|
|
128
|
+
"PREREQUISITES:\n- If you provide `senderLinkedinUrl`, it is used as a campaign identity bootstrap signal, not as a connected-sender availability check.\n- `clientProspectId` is optional when sender URL is available and allows a direct materialized campaign identity context.\n- `clientProspectId` is preferred for deterministic campaign identity resolution.",
|
|
129
129
|
inputSchema: {
|
|
130
130
|
type: "object",
|
|
131
131
|
properties: {
|
|
@@ -139,13 +139,13 @@ export const campaignToolDefinitions = [
|
|
|
139
139
|
},
|
|
140
140
|
clientProspectId: {
|
|
141
141
|
type: "string",
|
|
142
|
-
description: "Use this for existing
|
|
142
|
+
description: "Use this for existing campaign identity/client prospect rows. For brand-new campaign identities, pass `senderLinkedinUrl` and the backend will attempt prospect lookup/creation during campaign creation.",
|
|
143
143
|
},
|
|
144
144
|
// `senderLinkedinUrl` (not `linkedinUrl`) to disambiguate from
|
|
145
145
|
// prospect-side `linkedinUrl` fields used in other tools (research-prospect etc.).
|
|
146
146
|
senderLinkedinUrl: {
|
|
147
147
|
type: "string",
|
|
148
|
-
description: "Optional
|
|
148
|
+
description: "Optional campaign identity LinkedIn profile URL. Use when the client prospect ID is not yet materialized and backend bootstrap should be used.",
|
|
149
149
|
},
|
|
150
150
|
offerPositioning: {
|
|
151
151
|
type: "object",
|
|
@@ -623,7 +623,7 @@ export async function createCampaign(input) {
|
|
|
623
623
|
`or all create fields. Missing: ${missing.join(", ")}.\n\n` +
|
|
624
624
|
"Remediation:\n" +
|
|
625
625
|
'- For full workflow, call get_subskill_prompt({ subskillName: "create-campaign" }) and follow it.\n' +
|
|
626
|
-
"- For net-new campaign creation: run the `research-sender` flow first, call `complete_sender_research`, then pass either `clientProspectId` (preferred) or `senderLinkedinUrl` and let the backend resolve
|
|
626
|
+
"- For net-new campaign creation: run the `research-sender` flow first as campaign identity/client prospect research, call `complete_sender_research`, then pass either `clientProspectId` (preferred) or `senderLinkedinUrl` and let the backend resolve campaign identity context at campaign creation time.\n" +
|
|
627
627
|
"- For resume, call create_campaign with campaignId only.");
|
|
628
628
|
}
|
|
629
629
|
assertNetNewCreateCampaignResearchReady();
|
|
@@ -88,21 +88,21 @@ export function assertResearchPromptLoaded(mode = "any") {
|
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
if (mode === "sender") {
|
|
91
|
-
throw new Error('FLOW_PRECONDITION: net-new create_campaign requires
|
|
91
|
+
throw new Error('FLOW_PRECONDITION: net-new create_campaign requires campaign identity research preload. Call get_subskill_prompt({ subskillName: "research-sender" }) and run client/company prospect research before create_campaign.');
|
|
92
92
|
}
|
|
93
93
|
throw new Error("FLOW_PRECONDITION: research preload missing. Call get_subskill_prompt with the matching research wrapper (research-sender or research-prospect), then run research before continuing.");
|
|
94
94
|
}
|
|
95
95
|
export function assertNetNewCreateCampaignResearchReady() {
|
|
96
96
|
const senderResearchPromptState = researchPromptStates.sender;
|
|
97
97
|
if (!senderResearchPromptState) {
|
|
98
|
-
throw new Error('FLOW_PRECONDITION: net-new create_campaign requires
|
|
98
|
+
throw new Error('FLOW_PRECONDITION: net-new create_campaign requires campaign identity research preload. Call get_subskill_prompt({ subskillName: "research-sender" }) and run client/company prospect research before create_campaign.');
|
|
99
99
|
}
|
|
100
100
|
if (!senderResearchCompletionState) {
|
|
101
|
-
throw new Error("FLOW_PRECONDITION: completed
|
|
101
|
+
throw new Error("FLOW_PRECONDITION: completed campaign identity research is required before create_campaign. After running research-sender for client/company prospect context (parallel batch of fetch_linkedin_profile + fetch_company + WebSearches), call complete_sender_research({ depth, proofItemsFound, caseStudyItemsFound, credibilitySignalsFound, notes? }).");
|
|
102
102
|
}
|
|
103
103
|
if (new Date(senderResearchCompletionState.completedAt).getTime() <
|
|
104
104
|
new Date(senderResearchPromptState.loadedAt).getTime()) {
|
|
105
|
-
throw new Error("FLOW_PRECONDITION:
|
|
105
|
+
throw new Error("FLOW_PRECONDITION: campaign identity research completion is older than the latest research-sender prompt load. Re-run client/company prospect research and call complete_sender_research again.");
|
|
106
106
|
}
|
|
107
107
|
return {
|
|
108
108
|
ok: true,
|
package/dist/update-check.js
CHANGED
|
@@ -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
|
@@ -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`
|
|
@@ -198,9 +198,9 @@ Validated draft directory:
|
|
|
198
198
|
web lookup.
|
|
199
199
|
- Existing client prospect id: use it directly and do one company/profile
|
|
200
200
|
lookup only if a URL/domain is also available.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
Then summarize what you found in one or two lines and ask the user to confirm
|
|
202
|
+
the campaign identity/focus before continuing. Do not mention connected sender
|
|
203
|
+
availability in this confirmation.
|
|
204
204
|
- If the user did not provide the launch identity, ask in normal chat for the
|
|
205
205
|
LinkedIn profile or company website to use as the campaign identity. Do not ask
|
|
206
206
|
them to choose an input type with the structured question tool:
|
|
@@ -227,17 +227,19 @@ Validated draft directory:
|
|
|
227
227
|
three specific options plus `Other / custom`. Do not ask this as plain
|
|
228
228
|
numbered chat.
|
|
229
229
|
|
|
230
|
-
Then run one lightweight
|
|
231
|
-
|
|
230
|
+
Then run one lightweight campaign identity research pass before campaign
|
|
231
|
+
shell creation. The legacy subskill/tool names are `research-sender` and
|
|
232
|
+
`complete_sender_research`, but treat them as client/company prospect research
|
|
233
|
+
for the campaign, not as a connected-sender availability check. Prefer loading
|
|
232
234
|
`get_subskill_prompt({ subskillName: "research-sender" })`, running its
|
|
233
235
|
fetch/profile/company/WebSearch batch when those tools are exposed, and
|
|
234
236
|
calling `complete_sender_research`. If WebSearch is unavailable, use the
|
|
235
237
|
available MCP profile/company/post tools, call `complete_sender_research`
|
|
236
|
-
with the evidence counts found, and continue with explicit gaps.
|
|
237
|
-
questions should use the confirmed company context and
|
|
238
|
-
positioning options so they do not feel generic. If
|
|
239
|
-
unavailable, use neutral/custom intake options instead of
|
|
240
|
-
vertical-specific options.
|
|
238
|
+
with the evidence counts found, and continue with explicit gaps. Setup
|
|
239
|
+
questions and the campaign brief should use the confirmed company context and
|
|
240
|
+
researched proof / positioning options so they do not feel generic. If
|
|
241
|
+
identity is still unavailable, use neutral/custom intake options instead of
|
|
242
|
+
guessed vertical-specific options.
|
|
241
243
|
|
|
242
244
|
- Before the identity gate, use this customer-facing shape:
|
|
243
245
|
|
|
@@ -299,6 +301,14 @@ Validated draft directory:
|
|
|
299
301
|
Do not mention internal artifact names, local folders, shell commands, or
|
|
300
302
|
persistence in this preamble.
|
|
301
303
|
|
|
304
|
+
Before calling `create_campaign` for the watchable shell, make sure the
|
|
305
|
+
campaign identity research marker is satisfied: load `research-sender` if it
|
|
306
|
+
has not already been loaded, do the lightweight profile/company lookup, and
|
|
307
|
+
call `complete_sender_research`. This is still client/company prospect context
|
|
308
|
+
for the campaign brief. Do not call `list_senders`, do not ask the user to
|
|
309
|
+
connect a sender, and do not surface sender availability until
|
|
310
|
+
Settings/final handoff.
|
|
311
|
+
|
|
302
312
|
- Before asking for brief approval, render a slim approval brief in the chat and
|
|
303
313
|
keep the rich current brief in `brief.md`. Use rendered Markdown directly:
|
|
304
314
|
`##` heading, bold field labels, numbered section labels, and short bullets.
|
|
@@ -380,11 +390,11 @@ brief`, `Revise target`, `Revise offer/proof`, and `Other / custom`.
|
|
|
380
390
|
finish the write synchronously at that boundary.
|
|
381
391
|
|
|
382
392
|
- After the brief is approved or auto-confirmed, show the next progress line:
|
|
383
|
-
`Cool. Now I'm going to find people who are both a good fit and
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
393
|
+
`Cool. Now I'm going to find people who are both a good fit and active enough
|
|
394
|
+
to be worth a LinkedIn test. I'll compare source paths by expected volume,
|
|
395
|
+
sampled ICP fit, activity/warmth signal, cleanup risk, and tradeoffs. This
|
|
396
|
+
usually takes ~3-5 min, and I'll show you the source decision + sample before
|
|
397
|
+
anything goes live.`
|
|
388
398
|
- After the lead sample/source decision is ready and approved or auto-confirmed,
|
|
389
399
|
show the next progress line:
|
|
390
400
|
`Lead source is set. I'll import the first 10-row review batch into the
|
|
@@ -775,9 +785,13 @@ usable leads`.
|
|
|
775
785
|
- preview count
|
|
776
786
|
- ICP match rate with numerator/denominator and sample basis; never percent-only
|
|
777
787
|
- volume comparison
|
|
778
|
-
-
|
|
779
|
-
|
|
780
|
-
|
|
788
|
+
- source viability: expected source volume, expected usable leads after
|
|
789
|
+
filtering, source activity/warmth indicators, cleanup risk, and confidence
|
|
790
|
+
basis
|
|
791
|
+
- do not forecast connection acceptance, reply rate, meetings, pipeline,
|
|
792
|
+
revenue, or ROI unless the user supplied verified benchmark data for this
|
|
793
|
+
exact workspace/sender. If no verified benchmark exists, state that
|
|
794
|
+
performance is not estimated from this source review.
|
|
781
795
|
- for Signals-first paths: top candidate posts reviewed, selected post URLs,
|
|
782
796
|
post author, post topic/excerpt, post age or posted date, engagement count,
|
|
783
797
|
sampled engager count per selected post, sampled fit count per selected post,
|
|
@@ -801,7 +815,7 @@ customer-visible sections with literal headings:
|
|
|
801
815
|
- `## Source Decision`
|
|
802
816
|
- `## Evidence Snapshot`
|
|
803
817
|
- `## Selected Signal Posts` for Signals-first campaigns
|
|
804
|
-
- `##
|
|
818
|
+
- `## Source Viability`
|
|
805
819
|
- `## Sample Leads` for Signals-first campaigns
|
|
806
820
|
- `## Pros`
|
|
807
821
|
- `## Tradeoffs`
|
|
@@ -835,10 +849,11 @@ For Signals-first campaigns, `## Sample Leads` must group representative sample
|
|
|
835
849
|
rows by source post when possible, so the user can see not just that the search
|
|
836
850
|
found posts, but which posts produce believable prospects.
|
|
837
851
|
|
|
838
|
-
`##
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
852
|
+
`## Source Viability` must include expected source volume, expected usable
|
|
853
|
+
leads after filtering, source activity/warmth indicators, cleanup risk, and
|
|
854
|
+
estimate basis. Do not include likely connection acceptance or reply-rate
|
|
855
|
+
ranges unless verified benchmark data was supplied by the user for this exact
|
|
856
|
+
workspace/sender.
|
|
842
857
|
|
|
843
858
|
When showing `lead-review.md` to the user, render a slim decision summary in
|
|
844
859
|
chat, not the full evidence table. Use rendered Markdown directly with short
|
|
@@ -858,7 +873,8 @@ user-facing lead review. The visible response must include:
|
|
|
858
873
|
- `Why it won`
|
|
859
874
|
- `Quick numbers` as bullet points, with one provider/source angle per bullet.
|
|
860
875
|
Each bullet must include raw volume, sampled fit rate as `n/N`, estimated
|
|
861
|
-
good-fit range after cleanup,
|
|
876
|
+
good-fit range after cleanup, source activity/warmth basis, and confidence
|
|
877
|
+
note.
|
|
862
878
|
- If Signals was searched or considered, `Signal keyword lanes` as a compact
|
|
863
879
|
table with keyword lane, timeframe, posts found, and finalist posts reviewed.
|
|
864
880
|
- If Signals was searched or considered, `LinkedIn posts sampled` as a compact
|
|
@@ -112,23 +112,20 @@
|
|
|
112
112
|
"label": "Campaign brief interview",
|
|
113
113
|
"onEnter": [
|
|
114
114
|
{
|
|
115
|
-
"action": "
|
|
115
|
+
"action": "resolve_campaign_identity_before_strategy_packet",
|
|
116
116
|
"optional": false,
|
|
117
117
|
"when": "before_founder_strategy_source_packet",
|
|
118
118
|
"allowedTools": [
|
|
119
|
-
"list_senders",
|
|
120
|
-
"get_sender",
|
|
121
119
|
"fetch_company",
|
|
122
120
|
"fetch_linkedin_profile",
|
|
123
121
|
"WebFetch",
|
|
124
122
|
"WebSearch"
|
|
125
123
|
],
|
|
126
124
|
"maxCalls": {
|
|
127
|
-
"list_senders": 1,
|
|
128
125
|
"identityLookup": 1,
|
|
129
126
|
"companyLookupAfterIdentityConfirm": 1
|
|
130
127
|
},
|
|
131
|
-
"quietlyCheckConnectedSendersFirst":
|
|
128
|
+
"quietlyCheckConnectedSendersFirst": false,
|
|
132
129
|
"preferUserLinkedInWhenSenderInferenceIsWeak": true,
|
|
133
130
|
"doNotPresentSenderPickerBeforeIdentityInference": true,
|
|
134
131
|
"confirmCompanyBeforeStrategyQuestions": true,
|
|
@@ -149,7 +146,7 @@
|
|
|
149
146
|
"chatRenderRule": "If the sender/company context has multiple campaignable product lines, services, or offers, ask exactly one single-choice structured campaign-focus question before buyer/offer/proof/source. Do not ask numbered plain-chat choices when the structured question tool is available. Do not use checkbox or multi-select wording."
|
|
150
147
|
},
|
|
151
148
|
{
|
|
152
|
-
"action": "
|
|
149
|
+
"action": "run_campaign_identity_research_before_strategy_packet",
|
|
153
150
|
"target": "research-sender",
|
|
154
151
|
"when": "after_identity_and_campaign_focus_before_founder_strategy_source_packet",
|
|
155
152
|
"allowedTools": [
|
|
@@ -316,8 +313,6 @@
|
|
|
316
313
|
"get_subskill_asset",
|
|
317
314
|
"get_auth_status",
|
|
318
315
|
"get_active_workspace",
|
|
319
|
-
"list_senders",
|
|
320
|
-
"get_sender",
|
|
321
316
|
"complete_sender_research",
|
|
322
317
|
"fetch_company",
|
|
323
318
|
"fetch_company_posts",
|
|
@@ -475,13 +470,13 @@
|
|
|
475
470
|
{
|
|
476
471
|
"action": "render_find_leads_progress",
|
|
477
472
|
"requiredVisibleContent": [
|
|
478
|
-
"good fit and
|
|
473
|
+
"good fit and active enough to be worth a LinkedIn test",
|
|
479
474
|
"campaign source step",
|
|
480
475
|
"primary source",
|
|
481
476
|
"expected volume",
|
|
482
|
-
"
|
|
483
|
-
"
|
|
484
|
-
"
|
|
477
|
+
"sampled ICP fit",
|
|
478
|
+
"activity/warmth signal",
|
|
479
|
+
"cleanup risk",
|
|
485
480
|
"tradeoffs",
|
|
486
481
|
"search lanes",
|
|
487
482
|
"timeframe",
|
|
@@ -639,7 +634,6 @@
|
|
|
639
634
|
"sampled fits as n/N (%)",
|
|
640
635
|
"estimated usable people",
|
|
641
636
|
"estimated good-fit range after cleanup",
|
|
642
|
-
"expected reply-rate range",
|
|
643
637
|
"confidence note"
|
|
644
638
|
],
|
|
645
639
|
"sourceDecisionRequiredFields": [
|
|
@@ -668,7 +662,7 @@
|
|
|
668
662
|
"artifactLinkTiming": "before_next_step_or_revision_question",
|
|
669
663
|
"doNotCompressToSummaryOnly": false,
|
|
670
664
|
"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,
|
|
665
|
+
"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
666
|
},
|
|
673
667
|
{
|
|
674
668
|
"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
|
-
-
|
|
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
|
-
##
|
|
111
|
+
## Source Viability
|
|
112
112
|
|
|
113
113
|
- Source Volume: {n or range}
|
|
114
114
|
- Expected Usable Leads After Filtering: {n or range}
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
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
|
-
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
- `##
|
|
132
|
+
- `## Source Viability`
|
|
130
133
|
- `## Pros`
|
|
131
134
|
- `## Tradeoffs`
|
|
132
135
|
- `## Discarded Paths`
|
|
133
136
|
|
|
134
|
-
`##
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
|
347
|
-
by expected volume,
|
|
348
|
-
|
|
349
|
-
|
|
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
|