@sellable/mcp 0.1.77 → 0.1.79
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/README.md +8 -0
- package/agents/post-find-leads-filter-scout.md +67 -0
- package/agents/post-find-leads-message-scout.md +67 -0
- package/agents/registry.json +84 -0
- package/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/server.js +4 -1
- package/dist/tools/campaigns.js +3 -2
- package/dist/tools/prompts.d.ts +38 -0
- package/dist/tools/prompts.js +67 -2
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +17 -1
- package/skills/create-campaign-v2/SKILL.md +16 -4
- package/skills/create-campaign-v2/SOUL.md +8 -0
- package/skills/create-campaign-v2/core/flow.v2.json +9 -2
- package/skills/create-campaign-v2/references/filter-leads.md +88 -16
- package/skills/research/config.json +9 -0
package/README.md
CHANGED
|
@@ -243,6 +243,10 @@ Parallel execution contract:
|
|
|
243
243
|
- Source scout names come from `agents/registry.json` and are exposed at runtime
|
|
244
244
|
through `get_source_scout_registry`. Add new scouts there first; installer,
|
|
245
245
|
Codex config, Claude agent files, and prompts should consume the registry.
|
|
246
|
+
- Post-find-leads scout names also come from `agents/registry.json` and are
|
|
247
|
+
exposed through `get_post_find_leads_scout_registry`. After source approval,
|
|
248
|
+
use that registry to launch the filter-leads scout and message-generation
|
|
249
|
+
scout together when the host supports real subagents.
|
|
246
250
|
- Claude host: use the installed `source-scout-linkedin-engagement`,
|
|
247
251
|
`source-scout-sales-nav`, and `source-scout-prospeo-contact` Task/Agent subagents
|
|
248
252
|
for parallel lead-source scouting. Launch all credible lanes in one assistant
|
|
@@ -252,6 +256,10 @@ Parallel execution contract:
|
|
|
252
256
|
`source-scout-prospeo-contact`. Use `multi_tool_use.parallel` for independent
|
|
253
257
|
tool-call batches when subagents are unavailable or the work is only simple
|
|
254
258
|
batched lookups.
|
|
259
|
+
- For the post-lead stage, Codex/Claude should launch
|
|
260
|
+
`post-find-leads-filter-scout` and `post-find-leads-message-scout` in the
|
|
261
|
+
same turn/message when subagents are available. If not, run them sequentially
|
|
262
|
+
and do not claim parallel work.
|
|
255
263
|
- If neither backend is available, run sequentially with the same output schema.
|
|
256
264
|
|
|
257
265
|
Config path resolution (in order):
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
You are the Post-Lead Filter Scout for Sellable create-campaign-v2.
|
|
2
|
+
|
|
3
|
+
Your job starts only after find-leads has produced `lead-review.md` and
|
|
4
|
+
`lead-sample.json`, and the lead source has been approved or auto-confirmed.
|
|
5
|
+
Work only on the lead filter branch. Do not source new leads, draft messages,
|
|
6
|
+
import leads, create campaigns, ask the user questions, or mutate live campaign
|
|
7
|
+
state.
|
|
8
|
+
|
|
9
|
+
Required inputs:
|
|
10
|
+
|
|
11
|
+
- `brief.md`
|
|
12
|
+
- `lead-review.md`
|
|
13
|
+
- `lead-sample.json`
|
|
14
|
+
|
|
15
|
+
Required first steps:
|
|
16
|
+
|
|
17
|
+
1. Read the three required inputs.
|
|
18
|
+
2. Load the filter-leads reference before writing artifacts:
|
|
19
|
+
`get_subskill_asset({ subskillName: "create-campaign-v2", assetPath: "references/filter-leads.md" })`.
|
|
20
|
+
|
|
21
|
+
Owned outputs:
|
|
22
|
+
|
|
23
|
+
- `lead-filter.md`
|
|
24
|
+
- `rubric.json` when the filter is confirmed and production-shaped rubrics are
|
|
25
|
+
safe to write
|
|
26
|
+
|
|
27
|
+
Do not write or modify:
|
|
28
|
+
|
|
29
|
+
- `message-validation.md`
|
|
30
|
+
- `message-review.md`
|
|
31
|
+
- `approval-packet.md`
|
|
32
|
+
- `brief.md`
|
|
33
|
+
- `lead-review.md`
|
|
34
|
+
- `lead-sample.json`
|
|
35
|
+
|
|
36
|
+
Process:
|
|
37
|
+
|
|
38
|
+
1. Preserve the approved source decision and the sample math from
|
|
39
|
+
`lead-review.md`; do not re-run sourcing.
|
|
40
|
+
2. Turn the sample's good-fit and false-positive patterns into a strict but
|
|
41
|
+
campaign-native filter.
|
|
42
|
+
3. Include keep rules, exclude rules, sample false positives, pass-rate /
|
|
43
|
+
expected-yield impact, and a recommendation.
|
|
44
|
+
4. Add an explicit ability-to-pay or economic-capacity gate unless the brief
|
|
45
|
+
clearly says the offer is free or has no meaningful budget requirement.
|
|
46
|
+
5. Keep source mechanics out of production rubrics. Engagement, provider,
|
|
47
|
+
priority, or first-send ordering can inform prioritization, but they are not
|
|
48
|
+
standalone ICP qualification rules.
|
|
49
|
+
6. Write `lead-filter.md` first. If status is `confirmed`, also write
|
|
50
|
+
`rubric.json` with 2-5 production-shaped `leadScoringRubrics`.
|
|
51
|
+
|
|
52
|
+
Return a concise final status with:
|
|
53
|
+
|
|
54
|
+
- filter status: `confirmed`, `confirm-with-user`, or `revise-find-leads`
|
|
55
|
+
- artifacts written
|
|
56
|
+
- strongest keep rules
|
|
57
|
+
- strongest exclusion rules
|
|
58
|
+
- expected pass-rate / yield impact
|
|
59
|
+
- any blocker that prevents message review from joining
|
|
60
|
+
|
|
61
|
+
Quality bar:
|
|
62
|
+
|
|
63
|
+
- Every passing lead should be someone the user would be glad to hear back
|
|
64
|
+
from.
|
|
65
|
+
- Do not loosen the filter just to preserve volume.
|
|
66
|
+
- Do not make the filter so narrow that it contradicts the approved source
|
|
67
|
+
unless the sample evidence clearly requires it.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
You are the Post-Lead Message Scout for Sellable create-campaign-v2.
|
|
2
|
+
|
|
3
|
+
Your job starts only after find-leads has produced `lead-review.md` and
|
|
4
|
+
`lead-sample.json`, and the lead source has been approved or auto-confirmed.
|
|
5
|
+
Work only on the message generation branch. Do not source new leads, create lead
|
|
6
|
+
filters, import leads, create campaigns, ask the user questions, or mutate live
|
|
7
|
+
campaign state.
|
|
8
|
+
|
|
9
|
+
Required inputs:
|
|
10
|
+
|
|
11
|
+
- `brief.md`
|
|
12
|
+
- `lead-review.md`
|
|
13
|
+
- `lead-sample.json`
|
|
14
|
+
|
|
15
|
+
Required first steps:
|
|
16
|
+
|
|
17
|
+
1. Read the three required inputs.
|
|
18
|
+
2. Load 100% of the real generate-messages prompt with chunked
|
|
19
|
+
`get_subskill_prompt({ subskillName: "generate-messages", offset, limit })`
|
|
20
|
+
calls until `hasMore` is false.
|
|
21
|
+
|
|
22
|
+
Owned outputs:
|
|
23
|
+
|
|
24
|
+
- `message-validation.md`
|
|
25
|
+
- optional `message-prep.md`
|
|
26
|
+
- optional `message-candidate-drafts.md`
|
|
27
|
+
|
|
28
|
+
Do not write or modify:
|
|
29
|
+
|
|
30
|
+
- `lead-filter.md`
|
|
31
|
+
- `rubric.json`
|
|
32
|
+
- `message-review.md`
|
|
33
|
+
- `approval-packet.md`
|
|
34
|
+
- `brief.md`
|
|
35
|
+
- `lead-review.md`
|
|
36
|
+
- `lead-sample.json`
|
|
37
|
+
|
|
38
|
+
Process:
|
|
39
|
+
|
|
40
|
+
1. Run the loaded generate-messages workflow in dry mode from the approved
|
|
41
|
+
brief, lead-review source decision, and `lead-sample.json`.
|
|
42
|
+
2. Use `lead-sample.json` as the only lead sample source. Do not fetch new
|
|
43
|
+
prospects or invent richer row signals.
|
|
44
|
+
3. Build proof inventory, token fill rules, token adherence, angle drafts,
|
|
45
|
+
kill/combine review, finalists, skeptical-prospect review, winner gate, and
|
|
46
|
+
a raw sendable selected winner.
|
|
47
|
+
4. If `lead-filter.md` already exists, cite only basis rows that pass it. If it
|
|
48
|
+
does not exist yet, choose probable good-fit rows from `lead-sample.json` and
|
|
49
|
+
mark the final reconciliation as pending.
|
|
50
|
+
5. Write `message-validation.md`. Do not write `message-review.md`; the parent
|
|
51
|
+
thread owns the joined review after both post-lead scouts finish.
|
|
52
|
+
|
|
53
|
+
Return a concise final status with:
|
|
54
|
+
|
|
55
|
+
- artifacts written
|
|
56
|
+
- whether the full generate-messages prompt was loaded
|
|
57
|
+
- lead sample basis used
|
|
58
|
+
- selected winner summary
|
|
59
|
+
- whether final reconciliation with `lead-filter.md` is complete or pending
|
|
60
|
+
|
|
61
|
+
Quality bar:
|
|
62
|
+
|
|
63
|
+
- Do not synthesize a lightweight message from general knowledge. The artifact
|
|
64
|
+
must prove the full generate-messages workflow ran.
|
|
65
|
+
- Message generation can start before `lead-filter.md`, but message review
|
|
66
|
+
cannot start until the parent verifies the selected basis rows still pass the
|
|
67
|
+
final filter.
|
package/agents/registry.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
{
|
|
5
5
|
"id": "linkedin-engagement",
|
|
6
6
|
"name": "source-scout-linkedin-engagement",
|
|
7
|
+
"kind": "source-scout",
|
|
7
8
|
"promptFile": "source-scout-linkedin-engagement.md",
|
|
8
9
|
"displayName": "LinkedIn Engagement Scout",
|
|
9
10
|
"provider": "signal-discovery",
|
|
@@ -52,6 +53,7 @@
|
|
|
52
53
|
{
|
|
53
54
|
"id": "sales-nav",
|
|
54
55
|
"name": "source-scout-sales-nav",
|
|
56
|
+
"kind": "source-scout",
|
|
55
57
|
"promptFile": "source-scout-sales-nav.md",
|
|
56
58
|
"displayName": "Sales Nav Scout",
|
|
57
59
|
"provider": "sales-nav",
|
|
@@ -100,6 +102,7 @@
|
|
|
100
102
|
{
|
|
101
103
|
"id": "prospeo-contact",
|
|
102
104
|
"name": "source-scout-prospeo-contact",
|
|
105
|
+
"kind": "source-scout",
|
|
103
106
|
"promptFile": "source-scout-prospeo-contact.md",
|
|
104
107
|
"displayName": "Prospeo Contact Scout",
|
|
105
108
|
"provider": "prospeo",
|
|
@@ -145,6 +148,87 @@
|
|
|
145
148
|
"mcp__sellable__search_prospeo"
|
|
146
149
|
]
|
|
147
150
|
}
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"id": "filter-leads",
|
|
154
|
+
"name": "post-find-leads-filter-scout",
|
|
155
|
+
"kind": "post-find-leads-scout",
|
|
156
|
+
"promptFile": "post-find-leads-filter-scout.md",
|
|
157
|
+
"displayName": "Post-Lead Filter Scout",
|
|
158
|
+
"target": "filter-leads",
|
|
159
|
+
"inputs": ["brief.md", "lead-review.md", "lead-sample.json"],
|
|
160
|
+
"producesArtifacts": ["lead-filter.md"],
|
|
161
|
+
"optionalProducesArtifacts": ["rubric.json"],
|
|
162
|
+
"ownership": "lead quality, false-positive patterns, keep/exclude rules, ability-to-pay checks, and production rubric translation only",
|
|
163
|
+
"codex": {
|
|
164
|
+
"description": "Sellable post-find-leads scout for lead filtering and rubric generation after source approval.",
|
|
165
|
+
"model": "gpt-5.5",
|
|
166
|
+
"modelReasoningEffort": "high",
|
|
167
|
+
"sandboxMode": "workspace-write",
|
|
168
|
+
"nicknameCandidates": [
|
|
169
|
+
"Lead Filter Scout",
|
|
170
|
+
"Filter Scout",
|
|
171
|
+
"Rubric Scout"
|
|
172
|
+
]
|
|
173
|
+
},
|
|
174
|
+
"claude": {
|
|
175
|
+
"description": "Use proactively as a background Sellable post-find-leads scout after lead source approval to produce lead-filter.md and rubric.json from brief.md, lead-review.md, and lead-sample.json.",
|
|
176
|
+
"model": "inherit",
|
|
177
|
+
"background": true,
|
|
178
|
+
"maxTurns": 8,
|
|
179
|
+
"color": "yellow",
|
|
180
|
+
"tools": [
|
|
181
|
+
"Read",
|
|
182
|
+
"Write",
|
|
183
|
+
"Edit",
|
|
184
|
+
"Grep",
|
|
185
|
+
"Glob",
|
|
186
|
+
"mcp__sellable__get_subskill_prompt",
|
|
187
|
+
"mcp__sellable__get_subskill_asset"
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"id": "message-generation",
|
|
193
|
+
"name": "post-find-leads-message-scout",
|
|
194
|
+
"kind": "post-find-leads-scout",
|
|
195
|
+
"promptFile": "post-find-leads-message-scout.md",
|
|
196
|
+
"displayName": "Post-Lead Message Scout",
|
|
197
|
+
"target": "generate-messages",
|
|
198
|
+
"inputs": ["brief.md", "lead-review.md", "lead-sample.json"],
|
|
199
|
+
"producesArtifacts": ["message-validation.md"],
|
|
200
|
+
"optionalProducesArtifacts": [
|
|
201
|
+
"message-prep.md",
|
|
202
|
+
"message-candidate-drafts.md"
|
|
203
|
+
],
|
|
204
|
+
"ownership": "proof inventory, token strategy, angle drafting, skeptical-prospect review, and selected winner only",
|
|
205
|
+
"codex": {
|
|
206
|
+
"description": "Sellable post-find-leads scout for dry-mode message generation after source approval.",
|
|
207
|
+
"model": "gpt-5.5",
|
|
208
|
+
"modelReasoningEffort": "high",
|
|
209
|
+
"sandboxMode": "workspace-write",
|
|
210
|
+
"nicknameCandidates": [
|
|
211
|
+
"Message Scout",
|
|
212
|
+
"Message Generation Scout",
|
|
213
|
+
"Copy Scout"
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
"claude": {
|
|
217
|
+
"description": "Use proactively as a background Sellable post-find-leads scout after lead source approval to run dry-mode message generation from brief.md, lead-review.md, and lead-sample.json.",
|
|
218
|
+
"model": "inherit",
|
|
219
|
+
"background": true,
|
|
220
|
+
"maxTurns": 10,
|
|
221
|
+
"color": "magenta",
|
|
222
|
+
"tools": [
|
|
223
|
+
"Read",
|
|
224
|
+
"Write",
|
|
225
|
+
"Edit",
|
|
226
|
+
"Grep",
|
|
227
|
+
"Glob",
|
|
228
|
+
"mcp__sellable__get_subskill_prompt",
|
|
229
|
+
"mcp__sellable__get_subskill_asset"
|
|
230
|
+
]
|
|
231
|
+
}
|
|
148
232
|
}
|
|
149
233
|
]
|
|
150
234
|
}
|
package/dist/index-dev.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/server.js
CHANGED
|
@@ -21,7 +21,7 @@ import { fetchCompany, fetchCompanyPosts, fetchLinkedInPosts, fetchLinkedInProfi
|
|
|
21
21
|
import { getCampaignNavigationState, navigationToolDefinitions, } from "./tools/navigation.js";
|
|
22
22
|
import { addOnDemandLeads, createOnDemandCampaign, createOnDemandTable, initOnDemandSequence, onDemandToolDefinitions, pauseOnDemandCampaign, startOnDemandCampaign, } from "./tools/one-off.js";
|
|
23
23
|
import { processingToolDefinitions, upsertRubric } from "./tools/processing.js";
|
|
24
|
-
import { completeSenderResearch, getMessagePrompt, getSourceScoutRegistry, getSubskillAsset, getSubskillPrompt, listSubskillPrompts, promptToolDefinitions, searchSubskillPrompts, } from "./tools/prompts.js";
|
|
24
|
+
import { completeSenderResearch, getMessagePrompt, getPostFindLeadsScoutRegistry, getSourceScoutRegistry, getSubskillAsset, getSubskillPrompt, listSubskillPrompts, promptToolDefinitions, searchSubskillPrompts, } from "./tools/prompts.js";
|
|
25
25
|
import { readinessToolDefinitions, waitForCampaignTableReady, waitForLeadListReady, } from "./tools/readiness.js";
|
|
26
26
|
import { getRows, getTableRows, getTableRowsMinimal, rowToolDefinitions, } from "./tools/rows.js";
|
|
27
27
|
import { addRubricItem, checkRubric, deleteRubricItem, draftRubrics, rubricToolDefinitions, saveRubrics, selectNecessaryRubrics, updateRubricItem, waitForRubricResults, } from "./tools/rubrics.js";
|
|
@@ -411,6 +411,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
411
411
|
case "get_source_scout_registry":
|
|
412
412
|
result = getSourceScoutRegistry();
|
|
413
413
|
break;
|
|
414
|
+
case "get_post_find_leads_scout_registry":
|
|
415
|
+
result = getPostFindLeadsScoutRegistry();
|
|
416
|
+
break;
|
|
414
417
|
case "complete_sender_research":
|
|
415
418
|
result = completeSenderResearch(args);
|
|
416
419
|
break;
|
package/dist/tools/campaigns.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getApi } from "../api.js";
|
|
2
2
|
import { getConfig } from "../auth.js";
|
|
3
|
-
import { assertCreateCampaignPromptLoaded } from "./flow-preflight.js";
|
|
3
|
+
import { assertCreateCampaignPromptLoaded, assertNetNewCreateCampaignResearchReady, } from "./flow-preflight.js";
|
|
4
4
|
import { setCampaignInteractionMode, } from "./interaction-mode.js";
|
|
5
5
|
import { fetchCampaignRubrics } from "./processing.js";
|
|
6
6
|
const LEAD_SOURCE_PROVIDERS = {
|
|
@@ -618,9 +618,10 @@ export async function createCampaign(input) {
|
|
|
618
618
|
`or all create fields. Missing: ${missing.join(", ")}.\n\n` +
|
|
619
619
|
"Remediation:\n" +
|
|
620
620
|
'- For full workflow, call get_subskill_prompt({ subskillName: "create-campaign" }) and follow it.\n' +
|
|
621
|
-
"- For net-new campaign creation: pass either `clientProspectId` (preferred) or `senderLinkedinUrl` and let the backend resolve sender context at mint time.\n" +
|
|
621
|
+
"- 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 sender context at mint time.\n" +
|
|
622
622
|
"- For resume, call create_campaign with campaignId only.");
|
|
623
623
|
}
|
|
624
|
+
assertNetNewCreateCampaignResearchReady();
|
|
624
625
|
const name = input.name;
|
|
625
626
|
const clientProspectId = hasClientProspectId
|
|
626
627
|
? input.clientProspectId?.trim()
|
package/dist/tools/prompts.d.ts
CHANGED
|
@@ -96,6 +96,43 @@ export interface SourceScoutRegistryResponse {
|
|
|
96
96
|
parentThreadRule: string;
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
+
export interface PostFindLeadsScoutRegistryResponse {
|
|
100
|
+
version: number;
|
|
101
|
+
trigger: "find_leads_source_approved";
|
|
102
|
+
requiredArtifacts: string[];
|
|
103
|
+
scouts: Array<{
|
|
104
|
+
id: string;
|
|
105
|
+
name: string;
|
|
106
|
+
displayName: string;
|
|
107
|
+
target: string;
|
|
108
|
+
inputs: string[];
|
|
109
|
+
producesArtifacts: string[];
|
|
110
|
+
optionalProducesArtifacts: string[];
|
|
111
|
+
ownership: string;
|
|
112
|
+
codex: {
|
|
113
|
+
filename: string;
|
|
114
|
+
description: string;
|
|
115
|
+
model: string;
|
|
116
|
+
modelReasoningEffort: string;
|
|
117
|
+
};
|
|
118
|
+
claude: {
|
|
119
|
+
filename: string;
|
|
120
|
+
description: string;
|
|
121
|
+
tools: string[];
|
|
122
|
+
};
|
|
123
|
+
}>;
|
|
124
|
+
joinGate: {
|
|
125
|
+
afterAllComplete: boolean;
|
|
126
|
+
requiredArtifacts: string[];
|
|
127
|
+
show: string[];
|
|
128
|
+
nextStage: string;
|
|
129
|
+
};
|
|
130
|
+
usage: {
|
|
131
|
+
codex: string;
|
|
132
|
+
claude: string;
|
|
133
|
+
parentThreadRule: string;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
99
136
|
export declare const DEFAULT_SUBSKILL_PROMPT_CHUNK_CHARS = 48000;
|
|
100
137
|
export declare const MAX_SUBSKILL_PROMPT_CHUNK_CHARS = 48000;
|
|
101
138
|
export declare const promptToolDefinitions: ({
|
|
@@ -323,6 +360,7 @@ export declare const promptToolDefinitions: ({
|
|
|
323
360
|
_meta?: undefined;
|
|
324
361
|
})[];
|
|
325
362
|
export declare function getSourceScoutRegistry(): SourceScoutRegistryResponse;
|
|
363
|
+
export declare function getPostFindLeadsScoutRegistry(): PostFindLeadsScoutRegistryResponse;
|
|
326
364
|
export declare function getMessagePrompt(): Promise<PromptResponse>;
|
|
327
365
|
export declare function listSubskillPrompts(limit?: number, includePublic?: boolean, includeInternal?: boolean): ListSubskillPromptsResponse;
|
|
328
366
|
export declare function getSubskillPrompt(subskillName: string, offset?: number, limit?: number): SubskillPromptResponse;
|
package/dist/tools/prompts.js
CHANGED
|
@@ -140,6 +140,16 @@ export const promptToolDefinitions = [
|
|
|
140
140
|
additionalProperties: false,
|
|
141
141
|
},
|
|
142
142
|
},
|
|
143
|
+
{
|
|
144
|
+
name: "get_post_find_leads_scout_registry",
|
|
145
|
+
description: "Return the canonical Sellable post-find-leads scout names for the two parallel workstreams unlocked after lead source approval: filter-leads and message generation.",
|
|
146
|
+
inputSchema: {
|
|
147
|
+
type: "object",
|
|
148
|
+
properties: {},
|
|
149
|
+
required: [],
|
|
150
|
+
additionalProperties: false,
|
|
151
|
+
},
|
|
152
|
+
},
|
|
143
153
|
{
|
|
144
154
|
name: "complete_sender_research",
|
|
145
155
|
description: "Mark sender research as completed for create-campaign preflight. Call this after research-sender synthesis and before create_campaign.",
|
|
@@ -196,12 +206,22 @@ function resolveAgentsDir() {
|
|
|
196
206
|
}
|
|
197
207
|
return candidates[0] ?? path.resolve(process.cwd(), "mcp/sellable/agents");
|
|
198
208
|
}
|
|
199
|
-
|
|
209
|
+
function readAgentRegistry() {
|
|
200
210
|
const registryPath = path.join(resolveAgentsDir(), "registry.json");
|
|
201
211
|
const registry = JSON.parse(fs.readFileSync(registryPath, "utf8"));
|
|
202
|
-
const agents = Array.isArray(registry.agents) ? registry.agents : [];
|
|
203
212
|
return {
|
|
204
213
|
version: Number(registry.version || 1),
|
|
214
|
+
agents: Array.isArray(registry.agents) ? registry.agents : [],
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
export function getSourceScoutRegistry() {
|
|
218
|
+
const registry = readAgentRegistry();
|
|
219
|
+
const agents = registry.agents.filter((agent) => {
|
|
220
|
+
const kind = String(agent.kind || "source-scout");
|
|
221
|
+
return kind === "source-scout";
|
|
222
|
+
});
|
|
223
|
+
return {
|
|
224
|
+
version: registry.version,
|
|
205
225
|
agents: agents.map((agent) => ({
|
|
206
226
|
id: String(agent.id || ""),
|
|
207
227
|
name: String(agent.name || ""),
|
|
@@ -228,6 +248,51 @@ export function getSourceScoutRegistry() {
|
|
|
228
248
|
},
|
|
229
249
|
};
|
|
230
250
|
}
|
|
251
|
+
export function getPostFindLeadsScoutRegistry() {
|
|
252
|
+
const registry = readAgentRegistry();
|
|
253
|
+
const scouts = registry.agents.filter((agent) => String(agent.kind || "") === "post-find-leads-scout");
|
|
254
|
+
return {
|
|
255
|
+
version: registry.version,
|
|
256
|
+
trigger: "find_leads_source_approved",
|
|
257
|
+
requiredArtifacts: ["brief.md", "lead-review.md", "lead-sample.json"],
|
|
258
|
+
scouts: scouts.map((agent) => ({
|
|
259
|
+
id: String(agent.id || ""),
|
|
260
|
+
name: String(agent.name || ""),
|
|
261
|
+
displayName: String(agent.displayName || agent.name || ""),
|
|
262
|
+
target: String(agent.target || agent.id || ""),
|
|
263
|
+
inputs: Array.isArray(agent.inputs) ? agent.inputs.map(String) : [],
|
|
264
|
+
producesArtifacts: Array.isArray(agent.producesArtifacts)
|
|
265
|
+
? agent.producesArtifacts.map(String)
|
|
266
|
+
: [],
|
|
267
|
+
optionalProducesArtifacts: Array.isArray(agent.optionalProducesArtifacts)
|
|
268
|
+
? agent.optionalProducesArtifacts.map(String)
|
|
269
|
+
: [],
|
|
270
|
+
ownership: String(agent.ownership || ""),
|
|
271
|
+
codex: {
|
|
272
|
+
filename: String(agent.codex?.filename || `${agent.name}.toml`),
|
|
273
|
+
description: String(agent.codex?.description || ""),
|
|
274
|
+
model: String(agent.codex?.model || "gpt-5.5"),
|
|
275
|
+
modelReasoningEffort: String(agent.codex?.modelReasoningEffort || "high"),
|
|
276
|
+
},
|
|
277
|
+
claude: {
|
|
278
|
+
filename: String(agent.claude?.filename || `${agent.name}.md`),
|
|
279
|
+
description: String(agent.claude?.description || ""),
|
|
280
|
+
tools: Array.isArray(agent.claude?.tools) ? agent.claude.tools : [],
|
|
281
|
+
},
|
|
282
|
+
})),
|
|
283
|
+
joinGate: {
|
|
284
|
+
afterAllComplete: true,
|
|
285
|
+
requiredArtifacts: ["lead-filter.md", "message-validation.md"],
|
|
286
|
+
show: ["lead_filter_summary", "sample_message"],
|
|
287
|
+
nextStage: "message-review",
|
|
288
|
+
},
|
|
289
|
+
usage: {
|
|
290
|
+
codex: "After the user approves or auto-confirms the lead source, spawn both returned scout `name` values in one assistant turn when subagents are available.",
|
|
291
|
+
claude: "After lead source approval, invoke both returned Task/Agent subagents in one assistant message so filter-leads and message generation run concurrently.",
|
|
292
|
+
parentThreadRule: "Do not run filter-leads to completion before starting message generation. Both scouts consume brief.md, lead-review.md, and lead-sample.json; join before message review.",
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
}
|
|
231
296
|
export async function getMessagePrompt() {
|
|
232
297
|
const api = getApi();
|
|
233
298
|
return api.get("/api/v3/prompts/edit-message");
|
package/package.json
CHANGED
|
@@ -12,6 +12,7 @@ allowed-tools:
|
|
|
12
12
|
- mcp__sellable__search_subskill_prompts
|
|
13
13
|
- mcp__sellable__get_provider_prompt
|
|
14
14
|
- mcp__sellable__get_source_scout_registry
|
|
15
|
+
- mcp__sellable__get_post_find_leads_scout_registry
|
|
15
16
|
- mcp__sellable__get_message_prompt
|
|
16
17
|
- mcp__sellable__get_active_workspace
|
|
17
18
|
- mcp__sellable__list_senders
|
|
@@ -114,6 +115,13 @@ copy, is the runtime source of truth. If the host runs them sequentially, do not
|
|
|
114
115
|
claim they ran in parallel. In chat, call the downstream copy stage `message generation`;
|
|
115
116
|
`message-validation.md` is only an internal proof artifact.
|
|
116
117
|
|
|
118
|
+
After find-leads returns a lead source and the user approves it, use the same
|
|
119
|
+
registry pattern for the two post-lead branches. The create-campaign-v2 subskill
|
|
120
|
+
calls `get_post_find_leads_scout_registry`, then launches the returned
|
|
121
|
+
filter-leads scout and message-generation scout together when real subagents are
|
|
122
|
+
available. Message generation must not wait for the filter unless the host
|
|
123
|
+
cannot run the two branches concurrently.
|
|
124
|
+
|
|
117
125
|
Use rendered Markdown for user review surfaces, not fenced code blocks. Keep
|
|
118
126
|
lines short, use indexed section labels and bullets, and translate internal
|
|
119
127
|
sourcing terms into plain language.
|
|
@@ -190,14 +198,22 @@ Treat host capabilities as concrete functions, not prose conventions:
|
|
|
190
198
|
and continue chunks until `hasMore` is false.
|
|
191
199
|
- `load_source_scout_registry`: call
|
|
192
200
|
`mcp__sellable__get_source_scout_registry({})` before any scout dispatch.
|
|
201
|
+
- `load_post_find_leads_scout_registry`: call
|
|
202
|
+
`mcp__sellable__get_post_find_leads_scout_registry({})` after source
|
|
203
|
+
approval and before dispatching the post-lead filter/message scouts.
|
|
193
204
|
- `launch_source_scout`: Claude Code uses `Task` with `subagent_type` equal to
|
|
194
205
|
the registry `name`; Codex uses named custom agents such as
|
|
195
206
|
`source-scout-linkedin-engagement`, `source-scout-sales-nav`, and
|
|
196
207
|
`source-scout-prospeo-contact` when subagents are available.
|
|
208
|
+
- `launch_post_find_leads_scout`: Claude Code uses `Task` with `subagent_type`
|
|
209
|
+
equal to the returned post-lead registry `name`; Codex uses the returned
|
|
210
|
+
custom agents such as `post-find-leads-filter-scout` and
|
|
211
|
+
`post-find-leads-message-scout` when subagents are available.
|
|
197
212
|
|
|
198
213
|
If a required interactive host function is missing, stop and explain the
|
|
199
214
|
Sellable install/reload problem. Do not silently simulate structured choices,
|
|
200
|
-
subprompt loading, or
|
|
215
|
+
subprompt loading, source-scout dispatch, or post-lead scout dispatch with local
|
|
216
|
+
scripts.
|
|
201
217
|
|
|
202
218
|
Never narrate local draft housekeeping to the user. If you create directories,
|
|
203
219
|
save drafts, write artifacts, or persist intermediate state, translate it into
|
|
@@ -460,10 +460,12 @@ should test for this campaign. Those can run in parallel and usually take
|
|
|
460
460
|
`post-lead-workstreams` step. Launch `filter leads` and `message generation`
|
|
461
461
|
from the same basis (`brief.md`, `lead-review.md`, `lead-sample.json`) as
|
|
462
462
|
separate workstreams when the host supports real subagents/background work.
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
463
|
+
First call `get_post_find_leads_scout_registry` and use the returned
|
|
464
|
+
canonical `name` values. In Claude Code, use both returned Task/Agent
|
|
465
|
+
subagents in the same assistant message; in Codex, use both returned custom
|
|
466
|
+
scouts as disjoint subagents in the same assistant turn when the host exposes
|
|
467
|
+
them. The existing `filter-rubric` and `message-generation` steps remain
|
|
468
|
+
focused retry and resume targets.
|
|
467
469
|
- Message generation does not need `lead-filter.md` to start. The moment
|
|
468
470
|
`lead-sample.json` exists with at least 5 probable good-fit rows and the lead
|
|
469
471
|
source is confirmed or auto-confirmed, start the message-generation
|
|
@@ -499,6 +501,13 @@ should test for this campaign. Those can run in parallel and usually take
|
|
|
499
501
|
then draft the message from the same sample.` Never say `kicking off two
|
|
500
502
|
workstreams`, `in parallel`, or `background` unless parallel branches were
|
|
501
503
|
actually launched.
|
|
504
|
+
- For post-lead workstreams, first call
|
|
505
|
+
`get_post_find_leads_scout_registry` and launch exactly the returned
|
|
506
|
+
`filter-leads` and `message-generation` scouts when real subagents are
|
|
507
|
+
available. This is the same registry pattern as source scouting, but the
|
|
508
|
+
trigger is source approval and the join gate is both `lead-filter.md` and
|
|
509
|
+
`message-validation.md` existing from the same `brief.md`, `lead-review.md`,
|
|
510
|
+
and `lead-sample.json`.
|
|
502
511
|
- Never run a downstream stage until the active `flow.v2.json` step's
|
|
503
512
|
`requiredArtifacts` exist.
|
|
504
513
|
- Never call a tool outside the active step's `allowedTools`, and never call a
|
|
@@ -926,6 +935,9 @@ Required behavior:
|
|
|
926
935
|
economic capacity, competitor/vendor exclusion, and active current-role status
|
|
927
936
|
as table-stakes buyer-quality gates; include geography/market whenever budget,
|
|
928
937
|
channel adoption, language, compliance, or delivery assumptions depend on it
|
|
938
|
+
- customize the concrete thresholds for those gates to the client's offer,
|
|
939
|
+
market, price point, delivery model, and competitor landscape; the invariant
|
|
940
|
+
is that every passing lead should be worth the user's time if they reply
|
|
929
941
|
- do not turn "shown interest", post engagement, Signals source, recent posting,
|
|
930
942
|
provider source, or first-send priority into a production filter; those are
|
|
931
943
|
discovery or messaging context, not proof the lead is qualified
|
|
@@ -243,6 +243,14 @@ background source scouts` so the next turn has a user-visible request to spawn
|
|
|
243
243
|
scouts. If the host runs them sequentially, keep the output numeric but do not
|
|
244
244
|
claim the source scout was parallel.
|
|
245
245
|
|
|
246
|
+
For post-lead work, call `get_post_find_leads_scout_registry` after source
|
|
247
|
+
approval and use the returned canonical `name` values. Launch both returned
|
|
248
|
+
scouts in the same assistant turn/message when real subagents are available:
|
|
249
|
+
`post-find-leads-filter-scout` and `post-find-leads-message-scout`. This is the
|
|
250
|
+
same registry pattern as source scouting, but the trigger is approved
|
|
251
|
+
find-leads output and the join gate is both `lead-filter.md` and
|
|
252
|
+
`message-validation.md`.
|
|
253
|
+
|
|
246
254
|
Only promise parallel post-lead work when parallel work actually started. If the
|
|
247
255
|
host cannot or should not launch background branches, say the real sequence:
|
|
248
256
|
|
|
@@ -560,9 +560,15 @@
|
|
|
560
560
|
"label": "Post-lead filter and message workstreams",
|
|
561
561
|
"normalFlow": true,
|
|
562
562
|
"onEnter": [
|
|
563
|
+
{
|
|
564
|
+
"tool": "get_post_find_leads_scout_registry",
|
|
565
|
+
"requiredValues": {},
|
|
566
|
+
"purpose": "Load the canonical two-scout registry before dispatch so Codex and Claude use the same post-find-leads agent names."
|
|
567
|
+
},
|
|
563
568
|
{
|
|
564
569
|
"action": "launch_post_lead_workstreams",
|
|
565
570
|
"mode": "parallel_when_host_supports_subagents",
|
|
571
|
+
"registryRequired": "get_post_find_leads_scout_registry",
|
|
566
572
|
"branches": [
|
|
567
573
|
{
|
|
568
574
|
"name": "filter-leads",
|
|
@@ -587,8 +593,8 @@
|
|
|
587
593
|
],
|
|
588
594
|
"earlyMessageStartRule": "As soon as lead-sample.json exists with at least 5 probable good-fit rows and the lead source is confirmed or auto-confirmed, launch message-generation from brief.md, lead-review.md, and lead-sample.json. Do not wait for lead-filter.md to begin proof inventory, token planning, or candidate angles.",
|
|
589
595
|
"finalMessageReconcileRule": "message-validation.md may start before lead-filter.md exists, but before message-review it must cite only lead-sample.json rows that still pass lead-filter.md. If the selected winner depends on a row later excluded by lead-filter.md, revise message-generation before message review.",
|
|
590
|
-
"claudeRule": "In Claude Code, launch both
|
|
591
|
-
"codexRule": "In Codex, launch disjoint
|
|
596
|
+
"claudeRule": "In Claude Code, launch both returned post-find-leads scouts with Task/Agent subagents in the same assistant message when Task is available. Do not run filter first and then message generation unless subagents/background work are unavailable.",
|
|
597
|
+
"codexRule": "In Codex, launch both returned post-find-leads scout names as disjoint subagents in the same assistant turn when the host exposes subagents for this run. If the host cannot spawn them, run the same branches sequentially and say so.",
|
|
592
598
|
"fallback": "If real parallel branches are unavailable, run filter-leads and then message-generation in the parent thread. Do not claim background or parallel work in that fallback."
|
|
593
599
|
},
|
|
594
600
|
{
|
|
@@ -612,6 +618,7 @@
|
|
|
612
618
|
"allowedTools": [
|
|
613
619
|
"get_subskill_prompt",
|
|
614
620
|
"get_subskill_asset",
|
|
621
|
+
"get_post_find_leads_scout_registry",
|
|
615
622
|
"Task",
|
|
616
623
|
"spawn_agent",
|
|
617
624
|
"AskUserQuestion",
|
|
@@ -5,10 +5,16 @@ fidelity to the find-leads estimate, not re-run sourcing or produce a large
|
|
|
5
5
|
scoring framework.
|
|
6
6
|
|
|
7
7
|
The business goal is not "find people who might reply." It is "every reply the
|
|
8
|
-
user gets should come from someone
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
is not a good lead.
|
|
8
|
+
user gets should come from someone they would be excited to hear back from:
|
|
9
|
+
inside the ICP, able to act, and with a realistic path to buying." A lead who may
|
|
10
|
+
reply but cannot buy, lacks budget, sits at the wrong account type, is a
|
|
11
|
+
vendor/competitor, or is on the wrong side of a marketplace is not a good lead.
|
|
12
|
+
|
|
13
|
+
The exact qualification gates are client- and offer-specific, but the standard
|
|
14
|
+
does not change: anyone we reach out to, and anyone who replies, should be worth
|
|
15
|
+
the user's time to talk to. Use the client's price point, buyer, channel,
|
|
16
|
+
delivery constraints, market, and competitor landscape to define the concrete
|
|
17
|
+
gates for that campaign.
|
|
12
18
|
|
|
13
19
|
Source interest is not qualification. A lead who engaged with a post, appeared
|
|
14
20
|
in a Signals search, recently posted on LinkedIn, or "showed interest" in the
|
|
@@ -18,6 +24,34 @@ become a production filter or `leadScoringRubric` item. If the source lane was
|
|
|
18
24
|
built from topical engagement, the filter should still ask: is this the right
|
|
19
25
|
role, seniority, account type, budget band, market, and non-competitor?
|
|
20
26
|
|
|
27
|
+
Ability to pay must be considered for every campaign, but it is only a required
|
|
28
|
+
filter/rubric when the client, offer, or price point makes affordability a real
|
|
29
|
+
qualification risk. Do not force an enterprise-budget screen onto a low-cost B2C,
|
|
30
|
+
creator, prosumer, or small-team offer. Do not use a loose consumer-style screen
|
|
31
|
+
for an enterprise, services-heavy, implementation-heavy, or paid-pilot offer.
|
|
32
|
+
When affordability is material, `lead-filter.md` must name the campaign-native
|
|
33
|
+
proxy that proves the prospect can afford this specific offer at this specific
|
|
34
|
+
price point. Do not dodge this gate because the exact budget is unknown; use a
|
|
35
|
+
reasonable public proxy such as funding, headcount, revenue band, team maturity,
|
|
36
|
+
current tool spend, practice size, location count, consumer purchasing power,
|
|
37
|
+
job-to-be-done intensity, or buyer budget ownership. If affordability is material
|
|
38
|
+
and no reliable proxy exists in the sample or through normal enrichment, set
|
|
39
|
+
`Status: confirm-with-user` and ask for the budget proxy before moving to message
|
|
40
|
+
generation.
|
|
41
|
+
|
|
42
|
+
Use price-point proportionality:
|
|
43
|
+
|
|
44
|
+
- inexpensive B2C / prosumer / creator offers: do not require an explicit
|
|
45
|
+
ability-to-pay rule unless affordability is central to the ICP; fit is usually
|
|
46
|
+
based on use case, audience, life context, or intent, not company budget
|
|
47
|
+
- a few-hundred-dollar SMB or self-serve B2B offer: require evidence of an
|
|
48
|
+
active business, relevant workflow, and enough commercial seriousness to pay
|
|
49
|
+
hundreds, but do not require enterprise scale
|
|
50
|
+
- mid-market / paid pilot / agency or implementation-supported offer: require a
|
|
51
|
+
team, operational pain, and a likely owner for the budget
|
|
52
|
+
- enterprise / high-ACV offer: require enterprise or upper-mid-market account
|
|
53
|
+
fit, budget-owning seniority, department maturity, and buying-process plausibility
|
|
54
|
+
|
|
21
55
|
Inputs:
|
|
22
56
|
|
|
23
57
|
- `brief.md`
|
|
@@ -66,8 +100,8 @@ Use the actual sample to answer:
|
|
|
66
100
|
- which repeated false positives must become explicit exclusions
|
|
67
101
|
- whether filters are enough, or whether the source lane would make the
|
|
68
102
|
campaign miss if launched as-is
|
|
69
|
-
- whether the filtered leads are
|
|
70
|
-
|
|
103
|
+
- whether the filtered leads are worth sending to for this client's offer and
|
|
104
|
+
price point, using an economic-fit proxy only when affordability is material
|
|
71
105
|
|
|
72
106
|
## Table-Stakes Qualification Gates
|
|
73
107
|
|
|
@@ -75,6 +109,14 @@ Confirmed production filters should fail closed on buyer quality. The default
|
|
|
75
109
|
confirmed filter set must explicitly include each table-stakes gate below, or
|
|
76
110
|
`lead-filter.md` must state why a gate is irrelevant for this campaign:
|
|
77
111
|
|
|
112
|
+
Customize the concrete threshold for each gate to the client and offer. For
|
|
113
|
+
example, "can afford this" might mean nothing explicit for a low-cost B2C tool,
|
|
114
|
+
an active business for a few-hundred-dollar SMB offer, enterprise headcount for
|
|
115
|
+
one client, a funded seed-stage team for another, multi-location practice size
|
|
116
|
+
for another, or existing tool spend for another. Do not hard-code Sellable's
|
|
117
|
+
exact budget, geography, or title rules into unrelated campaigns; hard-code the
|
|
118
|
+
principle that passing leads must be worth the customer's time.
|
|
119
|
+
|
|
78
120
|
- right role / function: the person owns or directly influences the buyer
|
|
79
121
|
problem; wrong-function leads fail even when they match the source topic
|
|
80
122
|
- right seniority / authority: the person can approve, pilot, champion, or
|
|
@@ -83,9 +125,10 @@ confirmed filter set must explicitly include each table-stakes gate below, or
|
|
|
83
125
|
- account and channel fit: the company is the right account type and its buyers
|
|
84
126
|
are reachable through the chosen channel, such as LinkedIn for LinkedIn
|
|
85
127
|
outbound campaigns
|
|
86
|
-
- economic capacity / ability to buy: the
|
|
87
|
-
proxy for the offer, such as
|
|
88
|
-
|
|
128
|
+
- economic capacity / ability to buy, when material: the prospect has an
|
|
129
|
+
appropriate price-point proxy for the offer, such as active business status,
|
|
130
|
+
headcount, revenue, funding, team size, practice size, location count,
|
|
131
|
+
department maturity, existing tooling, or budget ownership
|
|
89
132
|
- competitor / vendor / wrong-side exclusion: competitors, adjacent vendors,
|
|
90
133
|
agencies/service providers, resellers, and marketplace-side conflicts fail
|
|
91
134
|
unless the brief explicitly targets that group
|
|
@@ -140,11 +183,15 @@ Status: confirmed | confirm-with-user | revise-find-leads
|
|
|
140
183
|
|
|
141
184
|
## Who We'll Keep
|
|
142
185
|
|
|
143
|
-
-
|
|
186
|
+
- buyers we would be excited to get a reply from, including the role, authority,
|
|
187
|
+
account type, and price-point-appropriate commercial-fit signal that make the
|
|
188
|
+
reply worth taking
|
|
144
189
|
|
|
145
190
|
## Who We'll Exclude
|
|
146
191
|
|
|
147
|
-
-
|
|
192
|
+
- people who may reply but are not worth sending to because they lack authority,
|
|
193
|
+
lack a plausible budget path when budget is material, sit at the wrong account
|
|
194
|
+
type, or are competitors/vendors/wrong-side marketplace participants
|
|
148
195
|
|
|
149
196
|
## Sample False Positives
|
|
150
197
|
|
|
@@ -165,7 +212,9 @@ Status: confirmed | confirm-with-user | revise-find-leads
|
|
|
165
212
|
|
|
166
213
|
## Implementation Details
|
|
167
214
|
|
|
168
|
-
If `Status: confirmed`, include production rubrics
|
|
215
|
+
If `Status: confirmed`, include production rubrics. The `economic_capacity`
|
|
216
|
+
example below applies when affordability is material; omit it for inexpensive
|
|
217
|
+
B2C/prosumer/community offers where ability to pay is not a meaningful fit gate:
|
|
169
218
|
|
|
170
219
|
```json
|
|
171
220
|
{
|
|
@@ -187,6 +236,15 @@ If `Status: confirmed`, include production rubrics:
|
|
|
187
236
|
"isRequiredCheck": true,
|
|
188
237
|
"allowPartialCredit": false,
|
|
189
238
|
"strictMatching": false
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"checkName": "economic_capacity",
|
|
242
|
+
"description": "Prospect has a price-point-appropriate ability-to-pay proxy.",
|
|
243
|
+
"criterion": "Yes if public or enriched data shows the prospect is likely able to afford this specific offer using the campaign's chosen proxy, scaled to the price point. For low-cost B2C/prosumer offers, this may be personal fit and purchasing power. For a few-hundred-dollar SMB/self-serve offer, this may be an active business and relevant workflow. For paid-pilot, implementation-heavy, mid-market, or enterprise offers, this may require funding, revenue, headcount, department maturity, existing tool spend, location count, or budget-owner title. No if the prospect is structurally unable to buy at the offer's price point or missing the required proxy after enrichment.",
|
|
244
|
+
"reason": "Replies from accounts without a realistic budget path waste the user's time even when the person is warm or interested.",
|
|
245
|
+
"isRequiredCheck": true,
|
|
246
|
+
"allowPartialCredit": false,
|
|
247
|
+
"strictMatching": false
|
|
190
248
|
}
|
|
191
249
|
]
|
|
192
250
|
}
|
|
@@ -230,6 +288,15 @@ Rules:
|
|
|
230
288
|
inputs
|
|
231
289
|
- `leadScoringRubrics` must contain 2-5 production-shaped rubric items, not one
|
|
232
290
|
item per bullet
|
|
291
|
+
- confirmed `leadScoringRubrics` must include an explicit ability-to-pay /
|
|
292
|
+
economic-capacity check when affordability is material to fit: a few-hundred-
|
|
293
|
+
dollar B2B offer, paid pilot, implementation-heavy sale, mid-market sale, or
|
|
294
|
+
enterprise/high-ACV motion. Do not require this check for inexpensive B2C,
|
|
295
|
+
prosumer, creator, community, or otherwise low-friction offers unless
|
|
296
|
+
affordability is central to the ICP. When present, the check must be
|
|
297
|
+
price-point-appropriate for the client and offer: commercial-seriousness based
|
|
298
|
+
for a few hundred dollars, budget-owner based for mid-market/enterprise. Do not
|
|
299
|
+
rely on role fit, company fit, or source engagement to imply this.
|
|
233
300
|
- do not put source-path mechanics or send-priority hints into
|
|
234
301
|
`leadScoringRubrics`. Examples: recently posted on LinkedIn, came from a
|
|
235
302
|
Signals search, appeared in Sales Nav, was found by Prospeo, first-send wave,
|
|
@@ -249,9 +316,10 @@ Rules:
|
|
|
249
316
|
- right role / function fit
|
|
250
317
|
- buyer seniority / authority
|
|
251
318
|
- account or company-type fit
|
|
252
|
-
- economic capacity / ability to buy, using a campaign-native
|
|
253
|
-
headcount, revenue, funding, practice
|
|
254
|
-
department maturity, existing tooling,
|
|
319
|
+
- economic capacity / ability to buy, when material, using a campaign-native
|
|
320
|
+
proxy such as active business status, headcount, revenue, funding, practice
|
|
321
|
+
size, location count, patient volume, department maturity, existing tooling,
|
|
322
|
+
or budget-owner title
|
|
255
323
|
- geography / market, when relevant
|
|
256
324
|
- active-current-role safety
|
|
257
325
|
- hard exclusions for competitors, vendors, agencies, job seekers,
|
|
@@ -275,6 +343,7 @@ When relevant to the brief and sample, preserve these recurring families:
|
|
|
275
343
|
- buyer role / seniority
|
|
276
344
|
- wrong-function exclusions
|
|
277
345
|
- company-type exclusions
|
|
346
|
+
- economic capacity / ability-to-pay proxy
|
|
278
347
|
- competitor / vendor / intermediary exclusions
|
|
279
348
|
- geography
|
|
280
349
|
- company size
|
|
@@ -327,6 +396,9 @@ Rules:
|
|
|
327
396
|
`reason`, `isRequiredCheck`, `allowPartialCredit`, and `strictMatching`
|
|
328
397
|
- prefer 2-5 rubric criteria total; do not map every keep/exclude bullet into
|
|
329
398
|
its own scoring row
|
|
399
|
+
- include an explicit ability-to-pay criterion when affordability is material to
|
|
400
|
+
fit. It may be bundled with company size/stage only when the `checkName`,
|
|
401
|
+
`description`, and `criterion` still name the budget proxy directly.
|
|
330
402
|
- production rubric criteria should be buyer-quality gates, not execution
|
|
331
403
|
metadata. Do not create rubric rows for provider source, recently-posted
|
|
332
404
|
priority, first-send ordering, or other search mechanics unless the user
|
|
@@ -350,7 +422,7 @@ Recommended rubric grouping:
|
|
|
350
422
|
|
|
351
423
|
- buyer authority / role fit
|
|
352
424
|
- company / industry / provider-lane fit
|
|
353
|
-
- economic capacity / ability to buy
|
|
425
|
+
- economic capacity / ability to buy, when material
|
|
354
426
|
- geography / size / stage fit, when relevant
|
|
355
427
|
- competitor / vendor / wrong-side / repeated false-positive exclusion
|
|
356
428
|
- one optional buyer-quality qualifier, at most, only when it changes fit scoring
|