@sellable/mcp 0.1.154 → 0.1.156
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/agents/post-find-leads-filter-scout.md +6 -6
- package/agents/post-find-leads-message-scout.md +12 -11
- package/agents/source-scout-linkedin-engagement.md +29 -24
- package/agents/source-scout-prospeo-contact.md +3 -3
- package/agents/source-scout-sales-nav.md +3 -3
- package/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/tools/cells.js +1 -1
- package/dist/tools/leads.d.ts +1 -0
- package/dist/tools/leads.js +43 -25
- package/dist/tools/navigation.js +2 -2
- package/dist/tools/prompts.js +7 -7
- package/dist/tools/readiness.js +2 -2
- package/dist/tools/rubrics.js +1 -1
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +37 -28
- package/skills/create-campaign-v2/SKILL.md +39 -50
- package/skills/create-campaign-v2/SOUL.md +4 -4
- package/skills/create-campaign-v2/core/auto-execute.README.md +9 -9
- package/skills/create-campaign-v2/core/flow.v2.json +7 -7
- package/skills/create-campaign-v2/core/policy.md +1 -1
- package/skills/create-campaign-v2/references/approval-gate-framing.md +2 -2
- package/skills/create-campaign-v2/references/filter-leads.md +11 -11
- package/skills/create-campaign-v2/references/final-handoff-contract.md +4 -4
- package/skills/create-campaign-v2/references/sample-validation-loop.md +8 -8
- package/skills/create-campaign-v2/references/step-13-import-leads.md +19 -18
- package/skills/create-campaign-v2/references/step-15-re-cascade.md +2 -2
- package/skills/create-campaign-v2/references/watch-guide-narration.md +15 -15
- package/skills/create-campaign-v2-tail/SKILL.md +27 -27
- package/skills/create-rubric/SKILL.md +1 -1
- package/skills/find-leads/SKILL.md +2 -2
- package/skills/providers/prospeo.md +1 -1
- package/skills/providers/sales-nav.md +1 -1
- package/skills/providers/signal-discovery.md +31 -27
- package/skills/research/config.json +9 -0
|
@@ -7,13 +7,13 @@ on every revision round.
|
|
|
7
7
|
## Principle
|
|
8
8
|
|
|
9
9
|
We spend a bounded review/process sample (default 15 rows) to prove fit before
|
|
10
|
-
the user spends credits on the rest of the confirmed source list. The
|
|
10
|
+
the user spends credits on the rest of the confirmed source list. The setup loop has one job:
|
|
11
11
|
answer the question "do we have enough real passing examples for the user to
|
|
12
12
|
judge this campaign?" Message generation starts earlier: the first row that
|
|
13
13
|
passes filters is enough to begin observing or queueing Generate Message for
|
|
14
14
|
that passing row.
|
|
15
15
|
|
|
16
|
-
If the answer is yes, proceed to Step 15 messaging for the
|
|
16
|
+
If the answer is yes, proceed to Step 15 messaging for the initial campaign rows. If
|
|
17
17
|
the answer is no, diagnose whether the brief is wrong or the list is wrong,
|
|
18
18
|
and either revise brief autonomously OR escalate to the user — never
|
|
19
19
|
auto-revise leads.
|
|
@@ -25,7 +25,7 @@ auto-revise leads.
|
|
|
25
25
|
not a visible route)
|
|
26
26
|
- Approved message template/token rules exist in the campaign brief before any
|
|
27
27
|
enrichment or scoring cells are queued
|
|
28
|
-
- Confirmed campaign rows from Step 13, with
|
|
28
|
+
- Confirmed campaign rows from Step 13, with the internal execution slice from
|
|
29
29
|
`reviewBatchRowIds` (size: `importLimit`, default 15)
|
|
30
30
|
- Config from `auto-execute.yaml`: `sample.sampleSize`,
|
|
31
31
|
`sample.minProjectedPass`, `sample.maxRevisionRounds`
|
|
@@ -57,9 +57,9 @@ auto-revise leads.
|
|
|
57
57
|
scoring from the queued Enrich Prospect cells
|
|
58
58
|
|
|
59
59
|
6. wait_for_rubric_results(sample, targetCount = <cohortSize>, minPassedCount = 1)
|
|
60
|
-
- cohortSize = stats.totalRows of the enrichment batch, or the
|
|
60
|
+
- cohortSize = stats.totalRows of the enrichment batch, or the execution slice
|
|
61
61
|
count
|
|
62
|
-
- default targetCount=15 matches the default
|
|
62
|
+
- default targetCount=15 matches the default execution slice, but pass the
|
|
63
63
|
explicit batch count anyway so future larger expansion batches do not
|
|
64
64
|
accidentally stop early
|
|
65
65
|
(see §Known Tool Behaviors #3)
|
|
@@ -179,7 +179,7 @@ company, enrichCellId, enrichStatus) over the default shape.
|
|
|
179
179
|
|
|
180
180
|
### 5. `wait_for_rubric_results` can timeout with enough signal to decide
|
|
181
181
|
|
|
182
|
-
Observed: a 15-row
|
|
182
|
+
Observed: a 15-row internal execution slice may return `ready=false`, `reason="timeout"`,
|
|
183
183
|
and partial stats such as 12/15 scored, 4 passing, 4 messages generated. That is
|
|
184
184
|
enough to diagnose an underperforming sample. Waiting again without active
|
|
185
185
|
processing makes the experience feel frozen.
|
|
@@ -211,8 +211,8 @@ Worked examples with defaults (sampleSize=15, importLimit=15):
|
|
|
211
211
|
| 15 | 15 | Yes |
|
|
212
212
|
|
|
213
213
|
When non-default importLimit/sampleSize are configured, the math scales
|
|
214
|
-
the same way. In the default
|
|
215
|
-
import limit, so the projection is the actual
|
|
214
|
+
the same way. In the default internal-slice mode, the slice size equals the
|
|
215
|
+
import limit, so the projection is the actual pass count.
|
|
216
216
|
|
|
217
217
|
## Brief-vs-List Diagnosis
|
|
218
218
|
|
|
@@ -55,7 +55,7 @@ Supported branches:
|
|
|
55
55
|
`import_leads({ campaignOfferId })` for Signal Discovery unless selected posts
|
|
56
56
|
already exist on the campaign. Provider import materializes the source lead
|
|
57
57
|
list from the approved source-capacity plan; it is not the same target as the
|
|
58
|
-
default
|
|
58
|
+
default internal campaign-table execution slice.
|
|
59
59
|
- **Supplied LinkedIn profile CSV** — confirm `load_csv_linkedin_leads` only
|
|
60
60
|
after the user approves that supplied-list source. Batch/materialize the
|
|
61
61
|
uploaded CSV into a Sellable lead-list table. Persist the returned
|
|
@@ -74,7 +74,7 @@ Supported branches:
|
|
|
74
74
|
its `domainFilterId`, run a campaign-associated Prospeo people search with
|
|
75
75
|
`campaignOfferId`, provider prompt preflight, and `domainFilterId`, then
|
|
76
76
|
materialize the source list from that search before copying the confirmed
|
|
77
|
-
list into the campaign table and processing the first
|
|
77
|
+
list into the campaign table and processing the first internal execution slice.
|
|
78
78
|
|
|
79
79
|
## Campaign-Attached Source Contract
|
|
80
80
|
|
|
@@ -107,14 +107,14 @@ import_leads({
|
|
|
107
107
|
campaignOfferId,
|
|
108
108
|
targetLeadCount: <sourceCandidateTarget from approved good-fit math>,
|
|
109
109
|
// Signal Discovery only:
|
|
110
|
-
targetEngagerCount: <ceil(
|
|
110
|
+
targetEngagerCount: <ceil(targetHeadlineFitProspects / sampledHeadlinePassRate)>,
|
|
111
111
|
maxPostsToScrape: <postsNeeded from approved math>
|
|
112
112
|
})
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
Provider is inherited from the selected source decision (not re-selected here)
|
|
116
116
|
and should already be saved on the campaign before import. For Sales Nav and
|
|
117
|
-
Prospeo, `<sourceCandidateTarget>` is not the
|
|
117
|
+
Prospeo, `<sourceCandidateTarget>` is not the internal campaign-table execution slice. It is
|
|
118
118
|
the source-list export/materialization count from the approved source math. Aim
|
|
119
119
|
for about 1,000 source contacts by default and use the provider cap internally
|
|
120
120
|
when the raw pool is larger. If projected good fits remain below the target,
|
|
@@ -124,20 +124,21 @@ escalation logic so dedup ratios are visible.
|
|
|
124
124
|
|
|
125
125
|
For Signal Discovery, do not scrape every currently selected/promoted sample
|
|
126
126
|
post by default. Before `import_leads`, reconcile selected posts with the
|
|
127
|
-
approved source math. The default
|
|
128
|
-
|
|
129
|
-
raw engagers. If the sampled fit rate is stronger or weaker, use
|
|
130
|
-
|
|
131
|
-
approved provider limit, and select only
|
|
132
|
-
count. The planning floor is 10% projected
|
|
133
|
-
Discovery falls below that floor during the
|
|
134
|
-
plan before importing. After an approved
|
|
127
|
+
approved source math. The default headline-fit target is 300 and the planning
|
|
128
|
+
headline-pass assumption is 20%, so the default source-candidate plan is about
|
|
129
|
+
1,500 raw engagers. If the sampled headline-fit rate is stronger or weaker, use
|
|
130
|
+
that sampled rate for `ceil(targetHeadlineFitProspects / sampledHeadlinePassRate)`,
|
|
131
|
+
cap the source candidates at the approved provider limit, and select only
|
|
132
|
+
enough posts to reach that engager count. The planning floor is 10% projected
|
|
133
|
+
headline-fit rate; if Signal Discovery falls below that floor during the
|
|
134
|
+
pre-scrape sample, revise the source plan before importing. After an approved
|
|
135
|
+
scrape starts, do not discard a nonempty
|
|
135
136
|
completed source list just because it lands below the source-candidate target:
|
|
136
|
-
confirm/copy the completed list for
|
|
137
|
-
or switch provider if the
|
|
137
|
+
confirm/copy the completed list for campaign setup, then add more posts
|
|
138
|
+
or switch provider if the source quality or scale is not enough. The subsequent
|
|
138
139
|
`confirm_lead_list` call uses `reviewBatchLimit: 15`. It copies the confirmed
|
|
139
140
|
source rows into the campaign table and returns only the first 15 rows as the
|
|
140
|
-
|
|
141
|
+
internal campaign-table execution slice.
|
|
141
142
|
|
|
142
143
|
Harvest-specific interpretation: Signal Discovery post comments and reactions
|
|
143
144
|
are paged from Harvest at about 100 records per page, with production caps of
|
|
@@ -145,12 +146,12 @@ are paged from Harvest at about 100 records per page, with production caps of
|
|
|
145
146
|
headline-passing candidates after that scrape. Therefore `71 source rows` means
|
|
146
147
|
71 candidates passed headline/list filtering and were inserted; it does not
|
|
147
148
|
mean the post scrape stopped after 71 raw engagers. Treat raw visible engagement,
|
|
148
|
-
raw fetched pages, inserted source rows, and the
|
|
149
|
+
raw fetched pages, inserted source rows, and the internal campaign-table execution slice as
|
|
149
150
|
separate numbers.
|
|
150
151
|
|
|
151
152
|
For supplied direct lists, `confirm_lead_list` should receive
|
|
152
153
|
`reviewBatchLimit: 15` so the campaign table can hold the confirmed list while
|
|
153
|
-
the first 15 rows drive the
|
|
154
|
+
the first 15 rows drive the internal setup flow.
|
|
154
155
|
|
|
155
156
|
## `mode=add` Two-Step Handshake
|
|
156
157
|
|
|
@@ -241,7 +242,7 @@ cannot scale further without a new source lane.
|
|
|
241
242
|
- `import_leads` is allowed immediately after the concrete source-action
|
|
242
243
|
approval. It materializes the source list and then `confirm_lead_list` copies
|
|
243
244
|
the confirmed source rows into the campaign table while returning only the
|
|
244
|
-
first 15 rows for the
|
|
245
|
+
first 15 rows for the internal campaign-table execution slice. Enrichment and fit
|
|
245
246
|
scoring wait for saved rubrics/run conditions; message cells wait for the
|
|
246
247
|
approved message set.
|
|
247
248
|
- Step 13 MUST reuse an approved source already attached with `campaignOfferId`
|
|
@@ -10,7 +10,7 @@ to `awaiting-user-greenlight`, and on every resume into Step 15.
|
|
|
10
10
|
## Principle
|
|
11
11
|
|
|
12
12
|
Generate Message cells are cascade-scoped. If Step 14's rubric flips rows from
|
|
13
|
-
pending → passed AFTER Step 15 first observes messages for the
|
|
13
|
+
pending → passed AFTER Step 15 first observes messages for the initial campaign rows, the
|
|
14
14
|
new rows can sit pending with no message. That must not block the first review
|
|
15
15
|
handoff. Step 15 opens review as soon as one passing generated message exists;
|
|
16
16
|
late-passed rows can be re-cascaded after explicit user continuation or resume.
|
|
@@ -24,7 +24,7 @@ flat at 257. The new rows never got messages.
|
|
|
24
24
|
Re-cascade runs whenever ALL of the following are true:
|
|
25
25
|
|
|
26
26
|
1. The user has already approved the first generated message or explicitly asked
|
|
27
|
-
to continue processing more
|
|
27
|
+
to continue processing more campaign rows.
|
|
28
28
|
2. A subsequent check of rubric state shows rows that were pending at
|
|
29
29
|
first message-generation pass are now passed.
|
|
30
30
|
3. Those newly-passed rows do NOT yet have generated messages
|
|
@@ -49,13 +49,13 @@ states.
|
|
|
49
49
|
|
|
50
50
|
## Stages
|
|
51
51
|
|
|
52
|
-
| stage | UI label
|
|
53
|
-
| -------------- |
|
|
54
|
-
| `brief-review` | Brief review
|
|
55
|
-
| `find-leads` | Find Leads
|
|
56
|
-
| `review-batch` |
|
|
57
|
-
| `fit-message` | Fit + message
|
|
58
|
-
| `review-ready` | Review ready
|
|
52
|
+
| stage | UI label | Next |
|
|
53
|
+
| -------------- | -------------- | -------------- |
|
|
54
|
+
| `brief-review` | Brief review | Find Leads |
|
|
55
|
+
| `find-leads` | Find Leads | Campaign setup |
|
|
56
|
+
| `review-batch` | Campaign setup | Fit + message |
|
|
57
|
+
| `fit-message` | Fit + message | Review ready |
|
|
58
|
+
| `review-ready` | Review ready | Validation |
|
|
59
59
|
|
|
60
60
|
## Examples
|
|
61
61
|
|
|
@@ -138,7 +138,7 @@ Search iteration:
|
|
|
138
138
|
"stage": "find-leads",
|
|
139
139
|
"headline": "Tightening the search",
|
|
140
140
|
"visibleState": "The first Signal Discovery search was broad, so Codex is trying a narrower Claude Code founder lane.",
|
|
141
|
-
"agentIntent": "It is sampling a few engagers before scraping so the
|
|
141
|
+
"agentIntent": "It is sampling a few engagers before scraping so the source quality stays on-brief.",
|
|
142
142
|
"nextAction": "Review source math"
|
|
143
143
|
}
|
|
144
144
|
```
|
|
@@ -165,9 +165,9 @@ Review/process sample:
|
|
|
165
165
|
```json
|
|
166
166
|
{
|
|
167
167
|
"stage": "review-batch",
|
|
168
|
-
"headline": "Preparing
|
|
169
|
-
"visibleState": "This page shows the confirmed source leads. Codex will process the
|
|
170
|
-
"agentIntent": "Codex is preparing
|
|
168
|
+
"headline": "Preparing campaign setup",
|
|
169
|
+
"visibleState": "This page shows the confirmed source leads. Codex will process the initial campaign rows for setup.",
|
|
170
|
+
"agentIntent": "Codex is preparing filters and messages from those leads.",
|
|
171
171
|
"nextAction": "Fit + message"
|
|
172
172
|
}
|
|
173
173
|
```
|
|
@@ -179,8 +179,8 @@ Source approved and import starting:
|
|
|
179
179
|
"stage": "review-batch",
|
|
180
180
|
"headline": "Copying source leads",
|
|
181
181
|
"visibleState": "The browser is still showing the approved LinkedIn Engagement source candidates.",
|
|
182
|
-
"agentIntent": "Codex is copying the confirmed source into the campaign and will process only the
|
|
183
|
-
"nextAction": "
|
|
182
|
+
"agentIntent": "Codex is copying the confirmed source into the campaign and will process only the internal execution slice for setup.",
|
|
183
|
+
"nextAction": "Campaign setup ready"
|
|
184
184
|
}
|
|
185
185
|
```
|
|
186
186
|
|
|
@@ -282,8 +282,8 @@ Blocked/recovering:
|
|
|
282
282
|
```json
|
|
283
283
|
{
|
|
284
284
|
"stage": "review-batch",
|
|
285
|
-
"headline": "Fixing
|
|
286
|
-
"visibleState": "The browser is not showing
|
|
285
|
+
"headline": "Fixing campaign setup",
|
|
286
|
+
"visibleState": "The browser is not showing campaign rows yet.",
|
|
287
287
|
"agentIntent": "Codex is reconnecting the campaign state before moving forward.",
|
|
288
288
|
"nextAction": "Fit + message",
|
|
289
289
|
"blockedReason": "Campaign batch is not ready yet."
|
|
@@ -17,8 +17,8 @@ table.
|
|
|
17
17
|
## MANDATORY TOOL ORDER (read this BEFORE any tail step)
|
|
18
18
|
|
|
19
19
|
Every tail run MUST call these tools in this exact order. The tail is
|
|
20
|
-
**
|
|
21
|
-
the
|
|
20
|
+
**initial-slice cascade-driven**: you kick off Enrich Prospect only for
|
|
21
|
+
the initial campaign-table execution slice, and the workflow engine chains DNC Check →
|
|
22
22
|
ICP Score → Passes Rubric → Generate Message automatically. Your job is
|
|
23
23
|
to START the bounded cascade, WAIT until filter results land, OBSERVE message
|
|
24
24
|
generation as soon as one row passes, and stop for review.
|
|
@@ -26,13 +26,13 @@ Do NOT manually run rubric-check, enrich, or message-generation
|
|
|
26
26
|
tools — the cascade already does them.
|
|
27
27
|
|
|
28
28
|
```text
|
|
29
|
-
Step 13 — materialize source list + confirm
|
|
29
|
+
Step 13 — materialize source list + confirm initial campaign slice
|
|
30
30
|
materialize/reuse approved source with campaignOfferId
|
|
31
31
|
import_leads(source-list target; SalesNav/Prospeo default ~1000, Signal Discovery default ~1500 engagers)
|
|
32
32
|
wait_for_lead_list_ready
|
|
33
33
|
confirm_lead_list(reviewBatchLimit=15)
|
|
34
34
|
wait_for_campaign_table_ready # campaign table exists
|
|
35
|
-
get_rows_minimal # read
|
|
35
|
+
get_rows_minimal # read initial campaign-table execution slice
|
|
36
36
|
update_campaign(currentStep=filter-choice)
|
|
37
37
|
|
|
38
38
|
Post-import main thread
|
|
@@ -42,10 +42,10 @@ Post-import main thread
|
|
|
42
42
|
keep the watched app on Filter Leads after rubrics are saved
|
|
43
43
|
while on Filter Leads, show the message template recommendation from the background Message Draft Builder
|
|
44
44
|
after approve-message, update_campaign_brief writes `## Approved Message Template` with `{{...}}` tokens
|
|
45
|
-
only then start the
|
|
45
|
+
only then start the initial-slice cascade
|
|
46
46
|
|
|
47
|
-
Step 14 — kick
|
|
48
|
-
queue_cells(cellIds=<first 15
|
|
47
|
+
Step 14 — kick initial-slice cascade + observe campaign rows
|
|
48
|
+
queue_cells(cellIds=<first 15 campaign-table execution-slice Enrich Prospect cells only>) <-- starts bounded chain
|
|
49
49
|
wait_for_campaign_table_ready # wait until sample cascade starts returning filter results
|
|
50
50
|
get_rows_minimal # read passesRubric + message cell status per row
|
|
51
51
|
wait_for_rubric_results(minPassedCount=1, includeRows=false)
|
|
@@ -75,7 +75,7 @@ Step 16 — awaiting-user-greenlight
|
|
|
75
75
|
update_campaign(senderIds=[selectedSenderId], currentStep=sequence)
|
|
76
76
|
attach_recommended_sequence({ campaignId, currentStep: "send" }) # tier-aware: premium/SN -> If Open Profile->INMAIL_OPEN, else INVITE->accepted->DM
|
|
77
77
|
if the attach response did not move the UI: update_campaign(currentStep=send)
|
|
78
|
-
re-surface watchUrl +
|
|
78
|
+
re-surface watchUrl + campaign setup orientation + final launch choices
|
|
79
79
|
STOP. DO NOT call start_campaign. DO NOT move to running without explicit launch greenlight.
|
|
80
80
|
```
|
|
81
81
|
|
|
@@ -128,10 +128,10 @@ Message` column's http_request writes those cells via the cascade.
|
|
|
128
128
|
any are pending, call `queue_cells` on those generateMessageCellIds
|
|
129
129
|
and wait. If rows truly won't message, ESCALATE.
|
|
130
130
|
- You MAY NOT advance past Step 13 without calling `queue_cells` on
|
|
131
|
-
the
|
|
131
|
+
the initial-slice Enrich Prospect cells. Without it, every downstream
|
|
132
132
|
cell stays `pending` and the campaign ships empty.
|
|
133
|
-
- You MAY NOT queue enrichment for rows outside the configured
|
|
134
|
-
|
|
133
|
+
- You MAY NOT queue enrichment for rows outside the configured internal
|
|
134
|
+
execution slice before the user approves expansion. Full-list enrichment/message
|
|
135
135
|
generation is a credit-spend decision and must happen after the user
|
|
136
136
|
has reviewed the sample.
|
|
137
137
|
|
|
@@ -165,8 +165,8 @@ Entered from the lead-source confirmation path, with
|
|
|
165
165
|
import milestone.
|
|
166
166
|
|
|
167
167
|
> Reminder: every provider search you run from this point forward — the
|
|
168
|
-
>
|
|
169
|
-
>
|
|
168
|
+
> campaign setup source rerun in Step 13, any expansion search after the
|
|
169
|
+
> initial slice, alternate-lane probes, account-based reruns, and operator
|
|
170
170
|
> follow-ups — MUST include `campaignOfferId`. This applies to
|
|
171
171
|
> `search_prospeo`, `search_sales_nav`, `search_apollo`,
|
|
172
172
|
> `search_signals`, and any other provider search tool added later.
|
|
@@ -220,9 +220,9 @@ reviewBatchLimit: 15 })`. Do not call `import_leads` for this
|
|
|
220
220
|
`domainFilterId`; run a campaign-associated Prospeo people search with
|
|
221
221
|
`campaignOfferId`, provider prompt preflight, and that `domainFilterId`;
|
|
222
222
|
then import with `targetLeadCount` set to the approved source-list target
|
|
223
|
-
(default about 1,000). The first
|
|
224
|
-
|
|
225
|
-
|
|
223
|
+
(default about 1,000). The first copied campaign rows are the internal
|
|
224
|
+
execution slice; the full confirmed source list is copied into the campaign
|
|
225
|
+
for later expansion.
|
|
226
226
|
Persist or recover materialized IDs on resume: `leadListId`,
|
|
227
227
|
`domainFilterId`, `searchId`, `selectedLeadListId`, `workflowTableId`, and
|
|
228
228
|
imported row IDs. If the source file changed after preview, or an existing lead list
|
|
@@ -263,10 +263,10 @@ searchId, targetLeadCount: 1000 })`.
|
|
|
263
263
|
3. `wait_for_lead_list_ready` when a provider import job exists, then
|
|
264
264
|
`confirm_lead_list`. Persist both identifiers: `selectedLeadListId` remains
|
|
265
265
|
the source list and `workflowTableId` is the campaign table.
|
|
266
|
-
4. `wait_for_campaign_table_ready` until the
|
|
266
|
+
4. `wait_for_campaign_table_ready` until the initial campaign-table execution slice rows are
|
|
267
267
|
available in the campaign table.
|
|
268
|
-
5. Call `get_rows_minimal({ tableId: workflowTableId })` and confirm the
|
|
269
|
-
15-row
|
|
268
|
+
5. Call `get_rows_minimal({ tableId: workflowTableId })` and confirm the
|
|
269
|
+
15-row internal execution slice is present. Do not queue cells in Step 13.
|
|
270
270
|
6. If the import returns zero usable leads, ESCALATE per
|
|
271
271
|
`references/escalation-ladder.md` (hard fail).
|
|
272
272
|
7. `update_campaign({ campaignId, currentStep: "filter-choice" })`.
|
|
@@ -288,7 +288,7 @@ Do not route to a visible `validate-sample` step. Full decision tree lives in
|
|
|
288
288
|
`references/sample-validation-loop.md`.
|
|
289
289
|
|
|
290
290
|
**Step 14 starts the bounded fit cascade, then observes it.** Step 13 imported
|
|
291
|
-
the
|
|
291
|
+
the internal execution slice only. After `save_rubrics`, Step 14 queues the initial-slice
|
|
292
292
|
Enrich Prospect cells, waits until filter results start landing, then moves to
|
|
293
293
|
message observation as soon as one row passes and approved-template message
|
|
294
294
|
generation is ready. Step 15 opens review as soon as one passing generated message
|
|
@@ -351,9 +351,9 @@ Signals underfloor results), then offer revise-filter only if the imported rows
|
|
|
351
351
|
look close to ICP but the rubric is too strict. This prevents customer-visible
|
|
352
352
|
loops where the agent keeps asking to retry the same weak source.
|
|
353
353
|
|
|
354
|
-
When the
|
|
354
|
+
When the internal slice passes the projected-pass floor, call
|
|
355
355
|
`update_campaign({ campaignId, currentStep: "auto-execute-messaging" })`
|
|
356
|
-
and orient the user that messaging will complete for the
|
|
356
|
+
and orient the user that messaging will complete for the initial campaign rows only.
|
|
357
357
|
|
|
358
358
|
## Step 15: auto-execute-messaging
|
|
359
359
|
|
|
@@ -367,7 +367,7 @@ flow through the column pipeline: `Enrich Prospect` →
|
|
|
367
367
|
`DNC Check` → `ICP Score` → `Passes Rubric` → `Generate Message`.
|
|
368
368
|
Each column's http_request auto-fires when its upstream dependency
|
|
369
369
|
completes AND passes gate (e.g. `Passes Rubric === true` before
|
|
370
|
-
`Generate Message`). Your job in Step 15 is to WAIT for the
|
|
370
|
+
`Generate Message`). Your job in Step 15 is to WAIT for the initial-slice
|
|
371
371
|
cascade to reach `Generate Message` for rows that passed ICP, and verify
|
|
372
372
|
the output — not to generate messages manually.
|
|
373
373
|
|
|
@@ -536,14 +536,14 @@ runs.
|
|
|
536
536
|
|
|
537
537
|
## Tail Hard Rules
|
|
538
538
|
|
|
539
|
-
- Source-list materialization and
|
|
539
|
+
- Source-list materialization and initial-slice confirmation happen in Step 13,
|
|
540
540
|
not during atomic mint.
|
|
541
541
|
- Step 13 materializes/reuses the approved source with `campaignOfferId` before
|
|
542
542
|
import. Do not import a legacy campaignless Signal source until selected posts
|
|
543
543
|
exist on the campaign.
|
|
544
|
-
- Full-list expansion happens only after the
|
|
545
|
-
first enrichment/scoring pass must stay capped to the
|
|
546
|
-
|
|
544
|
+
- Full-list expansion happens only after the initial campaign setup proves out.
|
|
545
|
+
The first enrichment/scoring pass must stay capped to the internal
|
|
546
|
+
campaign-table execution slice.
|
|
547
547
|
- The tail NEVER calls `start_campaign` on its own.
|
|
548
548
|
- The tail NEVER auto-revises leads. Brief revision is autonomous; lead
|
|
549
549
|
revision is always operator-gated.
|
|
@@ -51,7 +51,7 @@ Create and save a comprehensive lead scoring rubric that:
|
|
|
51
51
|
|
|
52
52
|
## Rubric Validation + Results
|
|
53
53
|
|
|
54
|
-
- `mcp__sellable__get_rows_minimal` - Read
|
|
54
|
+
- `mcp__sellable__get_rows_minimal` - Read initial campaign-table execution-slice cell IDs
|
|
55
55
|
- `mcp__sellable__queue_cells` - Queue only bounded sample `enrichCellId` values
|
|
56
56
|
- `mcp__sellable__wait_for_rubric_results` - Poll pass-rate results
|
|
57
57
|
|
|
@@ -162,9 +162,9 @@ Execution flow:
|
|
|
162
162
|
- `campaignOfferId`
|
|
163
163
|
- `sourceLeadListId` (or omit to use `selectedLeadListId`)
|
|
164
164
|
- `jobId` (from `import_leads` when available; omit for direct CSV lead lists)
|
|
165
|
-
- `reviewBatchLimit: 15` for the
|
|
165
|
+
- `reviewBatchLimit: 15` for the internal campaign-table execution slice
|
|
166
166
|
9. For campaign-builder flows, `confirm_lead_list` owns the watched move to
|
|
167
|
-
`filter-choice` after the
|
|
167
|
+
`filter-choice` after the initial campaign-table execution slice exists. Then run:
|
|
168
168
|
- `wait_for_campaign_table_ready({ campaignId })`
|
|
169
169
|
- `get_campaign_context({ campaignId, refresh: true })`
|
|
170
170
|
- `get_rows_minimal({ tableId: workflowTableId, limit: 10, page: 1 })`
|
|
@@ -67,7 +67,7 @@ search_prospeo({
|
|
|
67
67
|
after cleanup should be at least 10%. Prospeo is the terminal fallback; if the
|
|
68
68
|
best reasonable Prospeo lane is still below 10%, tighten the ICP/source
|
|
69
69
|
direction instead of switching to another provider.
|
|
70
|
-
- After the list finishes and the user confirms it looks good, call `confirm_lead_list` with the `jobId` and `reviewBatchLimit: 15` to copy confirmed rows into the campaign table and use the first 15 as the
|
|
70
|
+
- After the list finishes and the user confirms it looks good, call `confirm_lead_list` with the `jobId` and `reviewBatchLimit: 15` to copy confirmed rows into the campaign table and use the first 15 as the internal campaign-table execution slice.
|
|
71
71
|
- `import_leads` owns the watched move to `confirm-lead-list` after a lead list/job exists.
|
|
72
72
|
- `confirm_lead_list` owns the watched move to `filter-choice` after confirmed campaign rows exist.
|
|
73
73
|
- Post-confirm readback order is required:
|
|
@@ -381,7 +381,7 @@ User: "Save it"
|
|
|
381
381
|
- `confirm_lead_list` - Copy confirmed lead list into campaign table
|
|
382
382
|
Parameters: campaignOfferId, sourceLeadListId (optional), reviewBatchLimit (optional, default 15), currentStep (optional)
|
|
383
383
|
Only call after user confirms the list looks good
|
|
384
|
-
Owns the filter-choice beat after campaign rows exist; process only the
|
|
384
|
+
Owns the filter-choice beat after campaign rows exist; process only the internal campaign-table execution slice until later approvals
|
|
385
385
|
</mcp_tools>
|
|
386
386
|
|
|
387
387
|
<limits>
|
|
@@ -24,10 +24,12 @@ When the user asks to find posts or start searching, **IMMEDIATELY begin Round 1
|
|
|
24
24
|
|
|
25
25
|
<lead_target>
|
|
26
26
|
|
|
27
|
-
- **Default create-campaign target: ~300
|
|
28
|
-
|
|
29
|
-
- **
|
|
30
|
-
|
|
27
|
+
- **Default create-campaign target: ~300 headline-fit prospects that pass the
|
|
28
|
+
Signal Discovery headline criteria for now.**
|
|
29
|
+
- **Use sample math first: required raw engagers =
|
|
30
|
+
`ceil(targetHeadlineFitProspects / sampledHeadlinePassRate)`. When no
|
|
31
|
+
stronger sample exists, assume ~20% of raw post engagers pass headline
|
|
32
|
+
filtering, so plan around ~1,500 raw engagers.**
|
|
31
33
|
- Provider/import caps are internal execution limits, not customer-facing
|
|
32
34
|
promises. Do not tell the user the internal provider cap.
|
|
33
35
|
- Quality > Quantity: a few hundred active users > 1000 potentially inactive profiles
|
|
@@ -47,8 +49,8 @@ number of engagers fetched. If a selected post has 1,200 visible engagers and
|
|
|
47
49
|
the source list lands at 71 rows, read that as 71 headline-passing inserted
|
|
48
50
|
rows, not as "only 71 engagers were scraped." Do not reject a completed
|
|
49
51
|
non-empty source list solely because inserted rows are below the raw engager
|
|
50
|
-
target; confirm/copy it for
|
|
51
|
-
|
|
52
|
+
target; confirm/copy it for campaign setup, then decide whether to add more
|
|
53
|
+
posts or switch lanes based on source quality and scale.
|
|
52
54
|
|
|
53
55
|
</harvest_scrape_contract>
|
|
54
56
|
|
|
@@ -112,23 +114,24 @@ You must estimate:
|
|
|
112
114
|
- `passRate`
|
|
113
115
|
- sampled pass rate used for extrapolation
|
|
114
116
|
- `goodFitPer100Engagers`
|
|
115
|
-
- normalized
|
|
116
|
-
after a conservative dedupe/cleanup factor
|
|
117
|
+
- normalized headline-pass rate as headline-fit prospects per 100 engagers
|
|
117
118
|
- `avgReachableEngagersPerPost`
|
|
118
119
|
- average reachable engagers per right-content post used for capacity math
|
|
119
120
|
- `goodFitProspectsPerPost`
|
|
120
|
-
- expected
|
|
121
|
+
- expected headline-fit prospects per right-content post
|
|
121
122
|
- `postsNeededForTarget`
|
|
122
123
|
- number of right-content posts needed to reach the target good-fit lead
|
|
123
124
|
count, defaulting to 300 for Signal Discovery unless the campaign says
|
|
124
125
|
otherwise
|
|
125
126
|
- `requiredEngagersToScrape`
|
|
126
|
-
- `ceil(
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
- `ceil(targetHeadlineFitProspects / sampledHeadlinePassRate)`; for example
|
|
128
|
+
a 35/60 sample is ~58%, so a 300 headline-fit target needs about 515 raw
|
|
129
|
+
engagers before adding a practical coverage buffer, not 3,000. The 10%
|
|
130
|
+
floor is a viability reject threshold, not the denominator when the sample
|
|
131
|
+
rate is higher.
|
|
129
132
|
- `planningFloor`
|
|
130
|
-
- minimum acceptable sampled/projected fit rate
|
|
131
|
-
|
|
133
|
+
- minimum acceptable sampled/projected headline-fit rate; default 10%.
|
|
134
|
+
Below this, do not scale Signal Discovery.
|
|
132
135
|
- `projectedRange`
|
|
133
136
|
- the conservative range implied by the observed sample
|
|
134
137
|
|
|
@@ -152,10 +155,10 @@ Use conservative logic:
|
|
|
152
155
|
- stale posts
|
|
153
156
|
- adjacent communities that are not actual buyers
|
|
154
157
|
4. Explain the pass-through briefly and explicitly:
|
|
155
|
-
- preferred: "`sampledCount`: 40, `passCount`: 9, `passRate`: ~22%, `goodFitPer100Engagers`: ~22
|
|
158
|
+
- preferred: "`sampledCount`: 40, `passCount`: 9, `passRate`: ~22%, `goodFitPer100Engagers`: ~22 headline-fit prospects, `requiredEngagersToScrape`: ~1,365 raw engagers for a 300 headline-fit target before a practical coverage buffer, `avgReachableEngagersPerPost`: 240, `goodFitProspectsPerPost`: ~53, `postsNeededForTarget`: ~6, `recentStrongPostCount`: 15-25, `freshEnoughPostCount`: 8-12, `projectedRange`: 300-380 from selected posts"
|
|
156
159
|
- fallback: "I could not fetch engagers, so this is inferred from post and author quality only"
|
|
157
160
|
5. If the evidence is too weak, say so and return a low-confidence estimate instead of pretending precision.
|
|
158
|
-
6. If sampled/projected fit
|
|
161
|
+
6. If sampled/projected headline-fit rate is below the 10% planning floor,
|
|
159
162
|
reject the Signal Discovery scrape path and recommend Sales Nav recent
|
|
160
163
|
activity as the next source.
|
|
161
164
|
7. Do not manually enumerate dozens of engagers in the final answer. Summarize the sample by `sampledCount`, `passCount`, `passRate`, `projectedRange`, and 3-6 representative examples.
|
|
@@ -411,20 +414,21 @@ recommendation, estimate source capacity from real sample math:
|
|
|
411
414
|
campaign says otherwise)
|
|
412
415
|
- eligible right-content posts by lane/content type
|
|
413
416
|
- reachable engagers from those posts
|
|
414
|
-
- sampled
|
|
415
|
-
-
|
|
416
|
-
- required engagers to scrape for the source target
|
|
417
|
+
- sampled headline-fit rate as `n/N` plus an easy percentage/range
|
|
418
|
+
- headline-fit prospects per 100 engagers
|
|
419
|
+
- required engagers to scrape for the source target using the sampled
|
|
420
|
+
headline-fit rate
|
|
417
421
|
- average reachable engagers per right-content post
|
|
418
|
-
- expected
|
|
422
|
+
- expected headline-fit leads per selected post
|
|
419
423
|
- posts needed to reach the target
|
|
420
|
-
- whether sampled/projected fit clears the 10% planning floor
|
|
424
|
+
- whether sampled/projected headline-fit rate clears the 10% planning floor
|
|
421
425
|
|
|
422
426
|
Then select the smallest right-content post set that plausibly hits the source
|
|
423
427
|
target. Do not scrape every promoted sample post by default; promoted sampling
|
|
424
428
|
state and final scrape plan are separate. If the math says the warm post lane
|
|
425
429
|
only supports a smaller first batch, say that and name the Sales Nav or Prospeo
|
|
426
430
|
scale fallback rather than padding the selection with noisy posts. If the
|
|
427
|
-
sampled/projected fit rate is below 10
|
|
431
|
+
sampled/projected headline-fit rate is below 10%, do not call
|
|
428
432
|
`import_leads`; move to Sales Nav recent activity.
|
|
429
433
|
|
|
430
434
|
```json
|
|
@@ -480,13 +484,13 @@ selections, headlineICPCriteria })`, then call
|
|
|
480
484
|
targetEngagerCount, maxPostsToScrape })` for the approved
|
|
481
485
|
source-capacity plan without asking for another yes/no gate. Then
|
|
482
486
|
`confirm_lead_list({ reviewBatchLimit: 15 })` copies confirmed source rows into
|
|
483
|
-
the campaign table and returns the
|
|
484
|
-
the source-candidate target with the
|
|
487
|
+
the campaign table and returns the internal campaign-table execution slice. Do not confuse
|
|
488
|
+
the source-candidate target with the execution-slice size.
|
|
485
489
|
If the completed source scrape comes back below the approved source-candidate
|
|
486
490
|
target but has usable rows, still call `confirm_lead_list` so the completed
|
|
487
|
-
source list is copied into the campaign and the
|
|
491
|
+
source list is copied into the campaign and the initial setup slice can run.
|
|
488
492
|
Treat the shortfall as a scale warning: add more approved posts or move to Sales
|
|
489
|
-
Nav only after
|
|
493
|
+
Nav only after source quality proves the lane is too thin or off-ICP.
|
|
490
494
|
|
|
491
495
|
The promotion/select step is required campaign state. Use post IDs from the
|
|
492
496
|
current campaign-scoped search result, not stale IDs copied from a source review
|
|
@@ -541,7 +545,7 @@ Then run post-confirm routing in this order:
|
|
|
541
545
|
leads (e.g., "Does this look right? Should I import leads now?").
|
|
542
546
|
`create-campaign-v2` tail flow: if the user already approved the source
|
|
543
547
|
decision, that approval is the import confirmation for the source list and
|
|
544
|
-
|
|
548
|
+
internal campaign setup slice; do not ask again.
|
|
545
549
|
6. If confirmation exists, call `import_leads`. If not, refine
|
|
546
550
|
selections/criteria and ask again.
|
|
547
551
|
7. When the lead list finishes and the user confirms it looks good, call
|