@sellable/mcp 0.1.151 → 0.1.153

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.
Files changed (37) hide show
  1. package/README.md +4 -3
  2. package/agents/post-find-leads-filter-scout.md +5 -4
  3. package/agents/post-find-leads-message-scout.md +15 -14
  4. package/agents/source-scout-linkedin-engagement.md +6 -5
  5. package/agents/source-scout-prospeo-contact.md +4 -4
  6. package/agents/source-scout-sales-nav.md +4 -4
  7. package/dist/index-dev.js +0 -0
  8. package/dist/index.js +0 -0
  9. package/dist/tools/cells.js +1 -1
  10. package/dist/tools/leads.d.ts +37 -3
  11. package/dist/tools/leads.js +85 -77
  12. package/dist/tools/prompts.js +9 -9
  13. package/dist/tools/readiness.d.ts +7 -1
  14. package/dist/tools/readiness.js +10 -17
  15. package/dist/tools/registry.d.ts +17 -0
  16. package/dist/tools/rubrics.js +23 -20
  17. package/package.json +1 -1
  18. package/skills/create-campaign/SKILL.md +59 -56
  19. package/skills/create-campaign-v2/SKILL.md +44 -42
  20. package/skills/create-campaign-v2/SOUL.md +16 -13
  21. package/skills/create-campaign-v2/core/auto-execute.README.md +16 -17
  22. package/skills/create-campaign-v2/core/auto-execute.yaml +8 -7
  23. package/skills/create-campaign-v2/core/flow.v2.json +81 -149
  24. package/skills/create-campaign-v2/core/policy.md +13 -12
  25. package/skills/create-campaign-v2/references/approval-gate-framing.md +4 -3
  26. package/skills/create-campaign-v2/references/filter-leads.md +5 -4
  27. package/skills/create-campaign-v2/references/lead-validation-preview.md +2 -2
  28. package/skills/create-campaign-v2/references/sample-validation-loop.md +32 -27
  29. package/skills/create-campaign-v2/references/step-13-import-leads.md +44 -33
  30. package/skills/create-campaign-v2/references/watch-guide-narration.md +27 -28
  31. package/skills/create-campaign-v2-tail/SKILL.md +44 -44
  32. package/skills/create-rubric/SKILL.md +5 -5
  33. package/skills/find-leads/SKILL.md +2 -2
  34. package/skills/generate-messages/SKILL.md +2 -1
  35. package/skills/providers/prospeo.md +3 -3
  36. package/skills/providers/sales-nav.md +7 -7
  37. package/skills/providers/signal-discovery.md +47 -23
@@ -1391,6 +1391,7 @@ export declare const allTools: ({
1391
1391
  campaignName?: undefined;
1392
1392
  keepInSync?: undefined;
1393
1393
  jobId?: undefined;
1394
+ reviewBatchLimit?: undefined;
1394
1395
  selections?: undefined;
1395
1396
  selectionMode?: undefined;
1396
1397
  };
@@ -1566,6 +1567,7 @@ export declare const allTools: ({
1566
1567
  campaignName?: undefined;
1567
1568
  keepInSync?: undefined;
1568
1569
  jobId?: undefined;
1570
+ reviewBatchLimit?: undefined;
1569
1571
  selections?: undefined;
1570
1572
  selectionMode?: undefined;
1571
1573
  };
@@ -1640,6 +1642,7 @@ export declare const allTools: ({
1640
1642
  campaignName?: undefined;
1641
1643
  keepInSync?: undefined;
1642
1644
  jobId?: undefined;
1645
+ reviewBatchLimit?: undefined;
1643
1646
  selections?: undefined;
1644
1647
  selectionMode?: undefined;
1645
1648
  };
@@ -1786,6 +1789,7 @@ export declare const allTools: ({
1786
1789
  campaignName?: undefined;
1787
1790
  keepInSync?: undefined;
1788
1791
  jobId?: undefined;
1792
+ reviewBatchLimit?: undefined;
1789
1793
  selections?: undefined;
1790
1794
  selectionMode?: undefined;
1791
1795
  };
@@ -1874,6 +1878,7 @@ export declare const allTools: ({
1874
1878
  campaignName?: undefined;
1875
1879
  keepInSync?: undefined;
1876
1880
  jobId?: undefined;
1881
+ reviewBatchLimit?: undefined;
1877
1882
  selections?: undefined;
1878
1883
  selectionMode?: undefined;
1879
1884
  };
@@ -1971,6 +1976,7 @@ export declare const allTools: ({
1971
1976
  campaignName?: undefined;
1972
1977
  keepInSync?: undefined;
1973
1978
  jobId?: undefined;
1979
+ reviewBatchLimit?: undefined;
1974
1980
  selections?: undefined;
1975
1981
  selectionMode?: undefined;
1976
1982
  };
@@ -2050,6 +2056,7 @@ export declare const allTools: ({
2050
2056
  campaignName?: undefined;
2051
2057
  keepInSync?: undefined;
2052
2058
  jobId?: undefined;
2059
+ reviewBatchLimit?: undefined;
2053
2060
  selections?: undefined;
2054
2061
  selectionMode?: undefined;
2055
2062
  };
@@ -2668,6 +2675,7 @@ export declare const allTools: ({
2668
2675
  campaignName?: undefined;
2669
2676
  keepInSync?: undefined;
2670
2677
  jobId?: undefined;
2678
+ reviewBatchLimit?: undefined;
2671
2679
  selections?: undefined;
2672
2680
  selectionMode?: undefined;
2673
2681
  };
@@ -2799,6 +2807,7 @@ export declare const allTools: ({
2799
2807
  campaignName?: undefined;
2800
2808
  keepInSync?: undefined;
2801
2809
  jobId?: undefined;
2810
+ reviewBatchLimit?: undefined;
2802
2811
  selections?: undefined;
2803
2812
  selectionMode?: undefined;
2804
2813
  };
@@ -2918,6 +2927,7 @@ export declare const allTools: ({
2918
2927
  campaignName?: undefined;
2919
2928
  keepInSync?: undefined;
2920
2929
  jobId?: undefined;
2930
+ reviewBatchLimit?: undefined;
2921
2931
  selections?: undefined;
2922
2932
  selectionMode?: undefined;
2923
2933
  };
@@ -2995,6 +3005,7 @@ export declare const allTools: ({
2995
3005
  campaignName?: undefined;
2996
3006
  keepInSync?: undefined;
2997
3007
  jobId?: undefined;
3008
+ reviewBatchLimit?: undefined;
2998
3009
  selections?: undefined;
2999
3010
  selectionMode?: undefined;
3000
3011
  };
@@ -3034,6 +3045,10 @@ export declare const allTools: ({
3034
3045
  type: string;
3035
3046
  description: string;
3036
3047
  };
3048
+ reviewBatchLimit: {
3049
+ type: string;
3050
+ description: string;
3051
+ };
3037
3052
  confirmed: {
3038
3053
  type: string;
3039
3054
  description: string;
@@ -3192,6 +3207,7 @@ export declare const allTools: ({
3192
3207
  campaignName?: undefined;
3193
3208
  keepInSync?: undefined;
3194
3209
  jobId?: undefined;
3210
+ reviewBatchLimit?: undefined;
3195
3211
  };
3196
3212
  required: string[];
3197
3213
  };
@@ -3271,6 +3287,7 @@ export declare const allTools: ({
3271
3287
  campaignName?: undefined;
3272
3288
  keepInSync?: undefined;
3273
3289
  jobId?: undefined;
3290
+ reviewBatchLimit?: undefined;
3274
3291
  selections?: undefined;
3275
3292
  selectionMode?: undefined;
3276
3293
  };
@@ -95,16 +95,16 @@ async function fetchCampaignOffer(campaignOfferId) {
95
95
  leadScoringRubrics: v3.rubrics,
96
96
  };
97
97
  }
98
- const filterLeadsReadyWatchNarration = {
98
+ const filterRulesSavedForReviewWatchNarration = {
99
99
  stage: "fit-message",
100
- headline: "Filter rules saved",
101
- visibleState: "The browser is staying on Filter Leads with the fit rules saved.",
102
- agentIntent: "Codex is preparing the message template for approval before enrichment, filtering, or message cells run.",
103
- nextAction: "Review the message template in chat",
100
+ headline: "Filter rules saved for review",
101
+ visibleState: "The browser is showing Filter Rules with the saved criteria.",
102
+ agentIntent: "Codex is waiting for filter approval before the review batch is enriched or scored.",
103
+ nextAction: "Approve or revise the filters",
104
104
  progressLabel: "Fit + message",
105
- safety: "Template approval comes before row execution.",
105
+ safety: "Saved rules are ready to review; downstream row processing remains gated.",
106
106
  };
107
- function shouldMoveToFilterLeads(campaign) {
107
+ function shouldKeepFilterRulesVisible(campaign) {
108
108
  const currentStep = campaign.currentStep;
109
109
  if (!currentStep)
110
110
  return true;
@@ -116,16 +116,15 @@ function shouldMoveToFilterLeads(campaign) {
116
116
  "filter-choice",
117
117
  "create-icp-rubric",
118
118
  "filter-rules",
119
- "apply-icp-rubric",
120
119
  ].includes(currentStep);
121
120
  }
122
121
  function buildEnableIcpFiltersPayload(campaign) {
123
122
  const payload = {
124
123
  enableICPFilters: true,
125
124
  };
126
- if (shouldMoveToFilterLeads(campaign)) {
127
- payload.currentStep = "apply-icp-rubric";
128
- payload.watchNarration = filterLeadsReadyWatchNarration;
125
+ if (shouldKeepFilterRulesVisible(campaign)) {
126
+ payload.currentStep = "create-icp-rubric";
127
+ payload.watchNarration = filterRulesSavedForReviewWatchNarration;
129
128
  }
130
129
  return payload;
131
130
  }
@@ -245,7 +244,7 @@ export const rubricToolDefinitions = [
245
244
  },
246
245
  {
247
246
  name: "save_rubrics",
248
- description: "Persist rubric criteria to the campaign. Pass leadScoringRubrics directly to save without drafting. Saving active rubrics enables ICP filtering and moves the watched client to Filter Leads; it does not run filtering by itself.",
247
+ description: "Persist rubric criteria to the campaign. Pass leadScoringRubrics directly to save without drafting. Saving active rubrics enables ICP filtering and keeps the watched client on Filter Rules for user approval; it does not move to Filter Leads or run filtering by itself.",
249
248
  inputSchema: {
250
249
  type: "object",
251
250
  properties: {
@@ -580,12 +579,16 @@ export async function saveRubrics(input) {
580
579
  // cascade blocked.
581
580
  let enableICPFiltersSet = false;
582
581
  let currentStepSet = false;
582
+ let savedCurrentStep = null;
583
583
  try {
584
584
  const api = getApi();
585
585
  const payload = buildEnableIcpFiltersPayload(campaign);
586
586
  await api.put(`/api/v2/campaign-offers/${input.campaignOfferId}`, payload);
587
587
  enableICPFiltersSet = true;
588
- currentStepSet = payload.currentStep === "apply-icp-rubric";
588
+ if (typeof payload.currentStep === "string") {
589
+ savedCurrentStep = payload.currentStep;
590
+ currentStepSet = true;
591
+ }
589
592
  }
590
593
  catch (error) {
591
594
  // Non-fatal: the rubric save already succeeded. Retry the minimum
@@ -604,17 +607,17 @@ export async function saveRubrics(input) {
604
607
  }
605
608
  return {
606
609
  success: true,
607
- message: currentStepSet
608
- ? `Saved ${normalizedDraft.length} rubric criteria, ICP filtering is ON, and the campaign is on Filter Leads.`
609
- : enableICPFiltersSet || campaign.enableICPFilters === true
610
+ message: savedCurrentStep === "create-icp-rubric"
611
+ ? `Saved ${normalizedDraft.length} rubric criteria, ICP filtering is ON, and the campaign is waiting for filter approval.`
612
+ : currentStepSet
610
613
  ? `Saved ${normalizedDraft.length} rubric criteria and ICP filtering is ON.`
611
- : `Saved ${normalizedDraft.length} rubric criteria to the campaign. WARNING: could not auto-enable ICP filtering — call update_campaign({ campaignId, enableICPFilters: true }) to activate rubric-based filtering.`,
614
+ : enableICPFiltersSet || campaign.enableICPFilters === true
615
+ ? `Saved ${normalizedDraft.length} rubric criteria and ICP filtering is ON.`
616
+ : `Saved ${normalizedDraft.length} rubric criteria to the campaign. WARNING: could not auto-enable ICP filtering — call update_campaign({ campaignId, enableICPFilters: true }) to activate rubric-based filtering.`,
612
617
  criteriaCount: normalizedDraft.length,
613
618
  deletedCount: deletedRubricIds.length,
614
619
  enableICPFiltersSet,
615
- currentStep: currentStepSet
616
- ? "apply-icp-rubric"
617
- : (campaign.currentStep ?? null),
620
+ currentStep: savedCurrentStep ?? campaign.currentStep ?? null,
618
621
  currentStepSet,
619
622
  rubrics: result?.rubrics ?? normalizedDraft,
620
623
  activeRubrics: result?.rubrics ?? normalizedDraft,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.151",
3
+ "version": "0.1.153",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -72,10 +72,10 @@ not create, link, or surface local draft files unless the user explicitly asks
72
72
  for them. Resume, gating, and handoff read campaign state first. The
73
73
  watchable campaign exists after the short brief; lead import is bounded to the
74
74
  first review batch. After that, the user chooses whether to use filters or skip.
75
- When filters are chosen, save rubrics, then pause before queueing enrichment or
76
- filtering: tell the user the fit rules are saved, the message template needs
77
- approval next, and enrichment/filtering will start after that approval. Use
78
- Template is the default message path; AI Generated is only an explicit opt-out.
75
+ When filters are chosen, save rubrics, get filter approval, then wait for
76
+ message-template approval before enrichment/filtering or Generate Message cells.
77
+ Use Template is the default message path; AI Generated is only an explicit
78
+ opt-out.
79
79
 
80
80
  ## Opening Turn Contract
81
81
 
@@ -124,9 +124,10 @@ data, compare sources by source volume, sampled ICP fit, activity/warmth
124
124
  signals, cleanup risk, and confidence basis. If a user asks for a forecast,
125
125
  label it explicitly as not estimated from this run.
126
126
 
127
- Before any provider prompt, search, source scout, or signal-discovery call,
128
- show a short source-plan gate and ask for approval. This first approval
129
- authorizes scouting/search only. The gate should say:
127
+ Before any provider prompt, search, source scout, or signal-discovery call, show
128
+ one source-plan gate and ask for approval. The plan must be visible before the
129
+ question, and this first approval authorizes scouting/search only. The gate
130
+ should say:
130
131
 
131
132
  - given this campaign, the viable source options
132
133
  - the recommended first lane
@@ -143,6 +144,10 @@ why. Do not call `search_signals`, `search_sales_nav`, `search_prospeo`,
143
144
  `fetch_post_engagers`, or provider-scoped subagents until the user approves this
144
145
  source plan or explicitly chooses a different source.
145
146
 
147
+ If the user already answered a provider approval such as "Approve Prospeo plan",
148
+ that answer satisfies the source-plan gate. Persist the approved provider and
149
+ run the scouting/search next; do not ask a second source-plan approval question.
150
+
146
151
  For hiring-led campaigns, do not default to Sales Nav just because the target is
147
152
  a role search. Prospeo is the primary lane when the brief asks for companies
148
153
  actively hiring specific roles, open-role signals, account/contact coverage, or
@@ -153,41 +158,42 @@ are likely. Sales Nav is useful for recent LinkedIn activity, role/title
153
158
  precision, and referral paths, but it does not provide hiring-by-role filters;
154
159
  say that distinction plainly in the source-plan gate.
155
160
 
156
- After scouting, ask for a second approval on the concrete source action. For
157
- Signal Discovery, name how many selected posts will be scraped, the target
158
- engager/source-candidate volume, and the bounded review-batch size. For Sales
159
- Nav or Prospeo, name the specific approved import lane and source lead count.
161
+ After scouting, ask for a second approval on the concrete source action. For
162
+ Signal Discovery, name how many selected posts will be scraped, the target
163
+ engager/source-candidate volume, and the 15-row review/process sample size. For Sales
164
+ Nav or Prospeo, name the specific approved import lane and source lead count.
165
+
160
166
  Do not call `import_leads` or `confirm_lead_list` until this second approval is
161
167
  granted.
162
168
 
163
- For Sales Nav and Prospeo, the second gate approves materializing the source
164
- lead list, not importing only the review batch. Use the first-page/sample review
165
- to calculate projected good fits: sampled fit rate after conservative cleanup,
166
- raw pool size, source target, and expected good-fit count. If the projected
167
- good-fit pool is below the campaign target (normally about 150+ usable
168
- prospects unless source defaults say otherwise), keep refining/broadening
169
- filters before asking for import approval. Once it clears target, approve
170
- `import_leads` with the source-list `targetLeadCount` (up to the raw count or
171
- provider max). Only after the source list is ready should `confirm_lead_list`
172
- clone the bounded review batch into the campaign table.
169
+ For Sales Nav and Prospeo, the second gate approves materializing the source
170
+ lead list, not importing only the review batch. Use the first-page/sample review
171
+ to calculate projected good fits: sampled fit rate after conservative cleanup,
172
+ raw pool size, source target, and expected good-fit count. If the projected
173
+ good-fit pool is below the campaign target, keep refining/broadening filters
174
+ before asking for import approval. Once it clears target, approve `import_leads`
175
+ with a source-list `targetLeadCount` around 1,000 by default (provider cap is
176
+ internal when the raw pool is larger). Only after the source list is ready
177
+ should `confirm_lead_list({ reviewBatchLimit: 15 })` copy confirmed rows into
178
+ the campaign table and return the first 15 review/process rows.
173
179
 
174
180
  For Signal Discovery, the customer-facing approval card must use the exact
175
181
  action shape "Approve scraping N Signal Discovery posts?" and the chat summary
176
182
  should be a compact `## Source Recommendation` block with:
177
183
 
178
- - good-fit target: about 150 prospects after cleanup, enrichment, and filters
179
- - source-candidate plan: about 1,000 raw engagers using a conservative 15%
180
- fit-rate assumption unless sampled data supports a different number
184
+ - goal: about 300 good-fit prospects after cleanup, enrichment, and filters
185
+ - source-candidate plan: about 1,500 raw engagers using a 20% working fit-rate
186
+ assumption unless sampled data supports a different number
181
187
  - planning floor: continue with Signal Discovery only when sampled/projected
182
188
  fit is at least 10% after cleanup; below that, move to Sales Nav recent
183
189
  activity instead of scraping noisy engagers
184
- - review checkpoint: after the source list exists, clone only the bounded
185
- review batch into the campaign for fit and message review
190
+ - review checkpoint: after the source list exists, copy confirmed source rows
191
+ into the campaign and process only the first 15 for fit and message review
186
192
  - a selected-post table with post author/topic, why it fits, and visible
187
193
  engagement
188
194
  - total visible pool and estimated good-fit pool
189
- - first pass: build the source list at the approved source-candidate target,
190
- then clone only the bounded review batch into the campaign
195
+ - first pass: build the source list, copy all confirmed source rows into the
196
+ campaign, then process only the first 15 rows before scaling
191
197
  - fallback: switch to Sales Nav recent activity if sampled/projected fit falls
192
198
  below 10%, or if the review batch is vendor-heavy, agency-heavy, or off-ICP
193
199
 
@@ -217,17 +223,19 @@ which posts are being sampled in the watched app. The watch guide should say
217
223
  that we are pulling sample engagers from these posts to confirm the ICP is
218
224
  actually engaging and the source is viable.
219
225
 
220
- After the bounded review batch exists, use the same registry pattern for
226
+ After confirmed source rows exist in the campaign table, use the same registry pattern for
227
+
221
228
  post-lead work, but do not load that registry or any deep filter/message prompt
222
229
  before the filter-choice question. After `confirm_lead_list`, ask add filters
223
230
  vs skip filters immediately. Once the user answers, launch the message scout
224
231
  from the same campaign/table basis. If the user chooses filters, also launch the
225
- filter-leads scout, move to Filter Rules, save rubrics, then keep the browser on
226
- Filter Leads while the message recommendation is reviewed. If the user skips
227
- filters, move to Messages/message review. Workflow cell execution still waits
228
- for filter and template approval. AI Generated is an explicit opt-out from the
229
- template path. If the post-lead agents are absent, the main thread still
230
- orchestrates the same branches from the compact context with MCP tools/assets.
232
+ filter-leads scout, move to Filter Rules, save rubrics, then ask for filter
233
+ approval. After approval, keep the browser on Filter Leads while the message
234
+ recommendation is reviewed. If the user skips filters, move to Messages/message
235
+ review. Enrichment/filtering and Generate Message cells wait for message
236
+ approval. AI Generated is an explicit opt-out from the template path. If the
237
+ post-lead agents are absent, the main thread still orchestrates the same
238
+ branches from compact MCP context.
231
239
 
232
240
  Use rendered Markdown for user review surfaces, not fenced code blocks. Keep
233
241
  lines short, use indexed section labels and bullets, and translate internal
@@ -643,29 +651,23 @@ updates.
643
651
  until `hasMore=false`. Message review requires Message Draft Builder output:
644
652
  do not draft from a checklist, local markdown artifact, or parent-thread
645
653
  intuition. Use campaign state, campaign brief content, selected source state, and
646
- imported review-batch rows as the source of truth; do not read stale local
654
+ first review/process sample rows as the source of truth; do not read stale local
647
655
  markdown such as `message-validation.md`, inspect the database directly, or
648
656
  synthesize local validation artifacts from general knowledge.
649
657
  5. Create the campaign shell early with the v1 brief so the user can open the
650
- watch link and see useful setup state immediately. Import only the first
651
- bounded review batch after the source is attached to the campaign; do not
652
- queue workflow cells, attach a sequence, or start until the filter choice is
653
- resolved, rubrics are saved when filters are enabled, template/token rules
654
- are approved on the default Use Template path, and the approved message set
655
- is synced into the campaign brief. When filters are approved, immediately
658
+ watch link and see useful setup state immediately. Materialize the approved
659
+ source list, copy confirmed rows into the campaign, and process only the
660
+ first 15 review rows after the source is attached to the campaign; do not
661
+ queue workflow cells, attach a sequence, or start until saved filters and the
662
+ message template/token rules are approved. When filters are chosen, immediately
656
663
  call `mcp__sellable__update_campaign({ campaignId, enableICPFilters: true, currentStep: "create-icp-rubric", watchNarration })`
657
664
  so the watched app moves to Filter Rules while rubrics are drafted/saved.
658
- After rubrics save, move the watched app to `apply-icp-rubric` / Filter
659
- Leads and say the fit rules are saved; the background message scout is
660
- preparing the message recommendation and approval comes next while the
661
- browser stays on Filter Leads. If filters are skipped, move the watched app to
662
- Messages/message review and wait for message approval there. After approval,
663
- save the template to the campaign brief, then queue the bounded review-batch
664
- `enrichCellId` cells to kick off enrichment/filtering. Move to Messages only
665
- after at least one review row passes and Generate Message cells are running or
666
- ready.
667
- Product Generate Message cells must not run before that template/token
668
- approval.
665
+ After rubrics save, keep Filter Rules visible for approval; after approval,
666
+ move to Filter Leads and wait there for the background message recommendation.
667
+ If filters are skipped, move to Messages/message review. Queue the bounded
668
+ review-batch `enrichCellId` cells only after message approval. Move to
669
+ Messages only after at least one review row passes and one generated message
670
+ is ready.
669
671
  Do not ask the user to approve the brief before shell creation unless they
670
672
  explicitly requested a no-write draft; the shell itself is the review surface.
671
673
  6. The main thread owns watch navigation. Call
@@ -673,9 +675,10 @@ updates.
673
675
  visible work so the user can watch progress in the app: `create-offer` for
674
676
  the brief, `pick-provider` or the selected provider step while sourcing,
675
677
  `filter-choice` after the review batch, `create-icp-rubric` as soon
676
- as filters are approved, `apply-icp-rubric` after rubrics save and while
677
- waiting for message-template approval, `validate-sample` while the approved
678
- template unlocks bounded enrichment/filter scoring on Filter Leads,
678
+ as filters are chosen and while saved filters await approval,
679
+ `apply-icp-rubric` after filter approval and message approval while bounded
680
+ enrichment/filter scoring runs, `validate-sample` only as a recovery/legacy
681
+ observation state,
679
682
  `auto-execute-messaging` after at least one row passes and review-batch
680
683
  messages are being generated or reviewed, `awaiting-user-greenlight` only
681
684
  after generated review-batch messages are approved, `settings` for sender
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: create-campaign-v2
3
- description: Execute the compact JSON-gated shell-first campaign flow: resolve campaign identity, create a watchable CampaignOffer shell with the brief, attach and approve the source, import the bounded review batch, persist rubrics and approved message template, validate the review batch, then hand off to Settings, sequence, and start.
3
+ description: Execute the compact JSON-gated shell-first campaign flow: resolve campaign identity, create a watchable CampaignOffer shell with the brief, attach and approve the source, copy the confirmed source list into the campaign, process the first 15 review rows, persist rubrics and approved message template, validate the first passing generated message, then hand off to Settings, sequence, and start.
4
4
  visibility: internal
5
5
  ---
6
6
 
@@ -40,19 +40,17 @@ for debug output.
40
40
  4. Create the watchable campaign shell with `create_campaign` and the v1 brief.
41
41
  5. Surface the direct watch link.
42
42
  6. Choose and approve the lead source.
43
- 7. Import and confirm only the bounded first review batch.
43
+ 7. Materialize the approved source list, confirm/copy it into the campaign, and
44
+ use only the first 15 rows as the initial review/process sample.
44
45
  8. Ask whether to use filters or skip them.
45
- 9. Persist lead rubrics when filters are enabled.
46
- 10. Generate a first-message template recommendation from the imported review
47
- rows.
48
- 11. Review and approve/revise the message.
49
- 12. Sync the approved template into the campaign brief.
50
- 13. After message approval, keep the watched app on Filter Leads while the
51
- bounded enrichment/filter cascade starts.
52
- 14. Move to Messages only after at least one review row passes and one generated
53
- message is ready for review. Do not wait for a stronger sample once that
54
- first passing message exists; review it, then hand off to Settings, sender,
55
- sequence, and explicit launch greenlight.
46
+ 9. Persist lead rubrics when filters are enabled, then ask approval while the
47
+ app remains on Filter Rules.
48
+ 10. Move to Filter Leads only after saved filters are approved.
49
+ 11. Review and approve/revise the message template.
50
+ 12. Sync the approved template into the brief, then queue bounded
51
+ enrichment/filtering.
52
+ 13. Move to Messages after one row passes and one generated message is ready;
53
+ review it, then hand off to Settings, sender, sequence, and launch.
56
54
 
57
55
  There is no normal approval-packet, commit-gate, atomic-mint, or local
58
56
  artifact-validation step. Those belong only to legacy validation/rehearsal
@@ -136,9 +134,9 @@ can be a conversation-signal check if relevant hiring posts are likely, and
136
134
  Sales Nav is a LinkedIn activity/referral fallback rather than the main hiring
137
135
  filter.
138
136
 
139
- Before any provider prompt, search, source scout, or signal-discovery call,
140
- show a short source-plan gate and ask for approval. This first approval
141
- authorizes source scouting/search only. The gate must say, in plain language:
137
+ Before any provider prompt, search, source scout, or signal-discovery call, show
138
+ one source-plan gate and ask for approval. The gate must include the plan before
139
+ the question, and this first approval authorizes source scouting/search only:
142
140
 
143
141
  - given this campaign, the viable source options
144
142
  - the recommended first lane
@@ -151,7 +149,9 @@ Do not surface blanket source heuristics as product copy. Make the recommendatio
151
149
  specific to the campaign. If Signal Discovery is recommended, name the exact
152
150
  post themes you will search. If the campaign looks unlikely to have relevant
153
151
  public conversations, recommend the specific Sales Nav or Prospeo lane instead
154
- and say why. Do not call `search_signals`, `search_sales_nav`, `search_prospeo`,
152
+ and say why. An approval like "Approve Prospeo plan" satisfies this gate; persist
153
+ the provider and search next. Do not ask a second source-plan question. Do not
154
+ call `search_signals`, `search_sales_nav`, `search_prospeo`,
155
155
  `fetch_post_engagers`, or provider-scoped subagents until the user approves this
156
156
  source plan or explicitly chooses a different source.
157
157
 
@@ -176,17 +176,17 @@ name the specific search/import lane and source lead count. Do not call
176
176
  `import_leads` or `confirm_lead_list` until this second source-action approval
177
177
  is granted.
178
178
 
179
- For Sales Nav and Prospeo, do not ask to import only the 25-row review batch at
179
+ For Sales Nav and Prospeo, do not ask to import only the 15-row review sample at
180
180
  the source-action gate. First-page samples are for source math: compute sampled
181
181
  fit after conservative cleanup, project how many good-fit prospects the raw
182
182
  pool can yield, and keep refining filters while the projected good-fit pool is
183
- below the campaign target (normally about 150+ usable prospects unless the
184
- campaign/source defaults say otherwise). Once the lane clears the target, ask
183
+ below the campaign target. Once the lane clears the target, ask
185
184
  approval to materialize the source list with
186
- `targetLeadCount = min(rawResultCount, providerMax, ceil(targetGoodFitLeads /
187
- projectedFitRateAfterCleanup))`. After that source list is ready,
188
- `confirm_lead_list` imports only the bounded review batch into the campaign
189
- table for fit and message review.
185
+ `targetLeadCount` around 1,000 source contacts by default (use the provider cap
186
+ internally when the raw pool is larger). After that source list is ready,
187
+ `confirm_lead_list({ reviewBatchLimit: 15 })` copies confirmed source rows into
188
+ the campaign table and returns the first 15 review/process row ids for fit and
189
+ message review.
190
190
 
191
191
  After the user approves this concrete source-action gate, do not show the
192
192
  Source Recommendation again and do not ask another source approval question.
@@ -205,10 +205,11 @@ selected posts exist:
205
205
 
206
206
  Use Signal Discovery first.
207
207
 
208
- **Good-fit target:** ~150 prospects after cleanup, enrichment, and filters<br>
209
- **Source-candidate plan:** scrape ~1,000 raw engagers using a conservative 15% fit-rate assumption<br>
208
+ **Goal:** ~300 good-fit prospects after cleanup, enrichment, and filters<br>
209
+ **Working assumption:** ~20% of raw post engagers become good-fit prospects<br>
210
+ **Engagers needed:** ~1,500 raw engagers<br>
210
211
  **Planning floor:** continue only when sampled/projected fit is at least 10% after cleanup; below that, switch to Sales Nav recent activity<br>
211
- **Review checkpoint:** after the source list exists, clone only the bounded review batch into the campaign for fit and message review<br>
212
+ **Review checkpoint:** after the source list exists, copy the entire confirmed source list into the campaign and process only the first 15 rows for fit and message review<br>
212
213
 
213
214
  ### Selected posts
214
215
 
@@ -219,19 +220,19 @@ Use Signal Discovery first.
219
220
  | Divyanshi Sharma | LinkedIn lead-gen system built with Claude Code | ~508 |
220
221
 
221
222
  **Total visible pool:** ~2,813 engagers<br>
222
- **Estimated good-fit pool at 15%:** ~420 prospects before dedupe/risk cleanup
223
+ **Estimated good-fit pool at 20%:** ~560 prospects before dedupe/risk cleanup
223
224
 
224
225
  ### Recommendation
225
226
 
226
227
  Approve scraping these 3 posts.
227
228
 
228
- This gives enough volume to work toward ~150 good-fit prospects, while
229
+ This gives enough volume to target ~300 good-fit prospects after cleanup, while
229
230
  keeping the source tied to people already engaging with Claude Code outbound /
230
231
  AI-native sales workflows.
231
232
 
232
- **First pass:** build the source list at the approved source-candidate target,
233
- then clone only the bounded review batch into the campaign so we can inspect
234
- fit and messages before sending.
233
+ **First pass:** build the source list, copy all confirmed source rows into the
234
+ campaign, then process only the first 15 rows so we can inspect quality before
235
+ scaling.
235
236
 
236
237
  **Fallback:** if sampled/projected fit falls below 10%, or if the review batch
237
238
  is too vendor-heavy, agency-heavy, or off-ICP, switch to Sales Nav recent
@@ -245,7 +246,7 @@ authorizes. For Sales Nav/Prospeo it must also show source export math:
245
246
  `rawResultCount`, `sampledFitRate`, conservative projected fit rate,
246
247
  `targetLeadCount` for the source list, and projected good-fit count from that
247
248
  export. If projected good-fit count is below target, the recommendation is to
248
- refine or broaden filters, not to import a 25-row batch.
249
+ refine or broaden filters, not to run a 15-row review sample.
249
250
 
250
251
  Supplied profile CSVs, company/domain CSVs, pasted domains, and existing
251
252
  Sellable lead lists are supported, but keep provider mechanics out of the first
@@ -253,7 +254,7 @@ customer-facing source-choice labels.
253
254
 
254
255
  ## Post-Lead Workstreams
255
256
 
256
- After `confirm_lead_list` imports a non-empty bounded review batch and
257
+ After `confirm_lead_list` copies a non-empty confirmed source into the campaign and
257
258
  `get_rows_minimal({ tableId: workflowTableId })` proves rows exist, ask the
258
259
  filter-choice question immediately. Do not call
259
260
  `get_post_find_leads_scout_registry`, load filter/message subskill prompts, or
@@ -271,11 +272,12 @@ are optional only.
271
272
  When the user chooses filters, immediately call
272
273
  `update_campaign({ campaignId, enableICPFilters: true, currentStep: "create-icp-rubric", watchNarration })`
273
274
  before rubric thinking or branch work. The watched app should move to Filter
274
- Rules quickly. After `save_rubrics`, the watched app should move to
275
- `apply-icp-rubric` / Filter Leads so the user can see the saved filters are
276
- ready and wait there for the background message agent. Tell the user explicitly
277
- that a message agent is drafting the first-message template while enrichment,
278
- filtering, and Generate Message cells remain blocked.
275
+ Rules quickly. After `save_rubrics`, keep the app on Filter Rules so the user
276
+ can read and approve the saved criteria. Only after that approval should
277
+ `update_campaign` move to `apply-icp-rubric` / Filter Leads, where the run waits
278
+ for the message template approval before enrichment, filtering, or Generate
279
+ Message cells are queued. Tell the user the Message Draft Builder is preparing
280
+ the template in the background.
279
281
 
280
282
  Lead Fit Builder persists production rubrics with `save_rubrics` when filters
281
283
  are enabled. It must not require `brief.md`, `lead-review.md`, or
@@ -311,11 +313,11 @@ state before drafting. Do not render message review until
311
313
 
312
314
  Load references only when needed:
313
315
 
314
- - `references/watch-link-handoff.md` for watch-link recovery and handoff copy.
315
- - `references/watch-guide-narration.md` for watched-step narration.
316
+ - `references/watch-link-handoff.md` for watch-link handoff.
317
+ - `references/watch-guide-narration.md` for watch narration.
316
318
  - `references/lead-validation-preview.md` for legacy/debug preview shapes.
317
319
  - `references/filter-leads.md` for rubric design and `save_rubrics` rules.
318
- - `references/step-13-import-leads.md` before review-batch import.
320
+ - `references/step-13-import-leads.md` before source copy.
319
321
  - `references/sample-validation-loop.md` before review-batch validation.
320
322
  - `references/final-handoff-contract.md` for Settings, sender, sequence, and
321
323
  start.