@sellable/mcp 0.1.148 → 0.1.150

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.
@@ -588,20 +588,9 @@
588
588
  ]
589
589
  },
590
590
  {
591
- "action": "launch_message_draft_builder_after_review_batch_import",
592
- "tool": "get_post_find_leads_scout_registry",
593
- "target": "post-find-leads-message-scout",
594
- "requiresNonEmptyRows": true,
595
- "mustRunBefore": [
596
- "filter-choice question",
597
- "filter approval",
598
- "save_rubrics"
599
- ],
600
- "mode": "background_when_host_supports_subagents",
601
- "fallback": "if no real background branch can start, say the real sequence and do not claim background drafting is running",
602
- "toolCallRequiredInBranch": "get_subskill_prompt({ subskillName: \"generate-messages\", offset, limit }) until hasMore=false",
603
- "runtimeProofTransport": "CampaignOffer.watchNarration.workerDetails.messageDraftBuilder",
604
- "purpose": "start the provisional message draft from the imported review batch immediately; do not defer this to filter approval"
591
+ "action": "summarize_review_batch_and_advance_to_filter_choice",
592
+ "purpose": "ask filter choice immediately; no post-lead registries, filter refs, or message prompts first",
593
+ "maxCustomerCopyLines": 4
605
594
  }
606
595
  ],
607
596
  "requiredCampaignState": [
@@ -611,8 +600,6 @@
611
600
  ],
612
601
  "allowedTools": [
613
602
  "get_subskill_prompt",
614
- "get_subskill_asset",
615
- "get_post_find_leads_scout_registry",
616
603
  "import_leads",
617
604
  "wait_for_lead_list_ready",
618
605
  "confirm_lead_list",
@@ -620,16 +607,18 @@
620
607
  "get_rows_minimal",
621
608
  "update_campaign",
622
609
  "AskUserQuestion",
623
- "request_user_input",
624
- "Task",
625
- "spawn_agent"
610
+ "request_user_input"
626
611
  ],
627
612
  "doNotAllow": [
613
+ "get_post_find_leads_scout_registry",
614
+ "Task",
615
+ "spawn_agent",
628
616
  "list_senders",
629
617
  "queue_cells",
630
618
  "start_campaign",
631
619
  "enrich_with_prospeo",
632
- "bulk_enrich_with_prospeo"
620
+ "bulk_enrich_with_prospeo",
621
+ "save_rubrics"
633
622
  ],
634
623
  "waitFor": "review_batch_imported",
635
624
  "transitions": {
@@ -659,6 +648,13 @@
659
648
  ]
660
649
  }
661
650
  ],
651
+ "hardRules": [
652
+ "ask_filter_choice_immediately_after_review_batch_import",
653
+ "do_not_call_get_subskill_prompt_before_filter_choice",
654
+ "do_not_call_get_subskill_asset_before_filter_choice",
655
+ "do_not_call_get_post_find_leads_scout_registry_before_filter_choice",
656
+ "do_not_spawn_post_lead_agents_before_filter_choice"
657
+ ],
662
658
  "requiredCampaignState": [
663
659
  "campaignId",
664
660
  "campaignBrief",
@@ -672,6 +668,11 @@
672
668
  "get_campaign_navigation_state"
673
669
  ],
674
670
  "doNotAllow": [
671
+ "get_subskill_prompt",
672
+ "get_subskill_asset",
673
+ "get_post_find_leads_scout_registry",
674
+ "Task",
675
+ "spawn_agent",
675
676
  "create_campaign",
676
677
  "list_senders",
677
678
  "import_leads",
@@ -693,7 +694,7 @@
693
694
  },
694
695
  {
695
696
  "id": "post-lead-workstreams",
696
- "label": "Filter and message workstreams",
697
+ "label": "Filter workstream",
697
698
  "onEnter": [
698
699
  {
699
700
  "action": "persist_add_filters_approval",
@@ -715,17 +716,18 @@
715
716
  },
716
717
  "mustRunBefore": [
717
718
  "get_post_find_leads_scout_registry",
718
- "launch_or_reuse_post_lead_workstreams",
719
+ "launch_lead_fit_builder_after_filter_choice",
719
720
  "save_rubrics"
720
721
  ]
721
722
  },
722
723
  {
723
724
  "tool": "get_post_find_leads_scout_registry",
724
- "purpose": "load canonical post-lead worker names"
725
+ "purpose": "load canonical post-lead worker names only after the user has chosen filters"
725
726
  },
726
727
  {
727
- "action": "launch_or_reuse_lead_fit_builder_and_existing_message_draft",
728
+ "action": "launch_lead_fit_builder_after_filter_choice",
728
729
  "mode": "parallel_when_host_supports_subagents",
730
+ "target": "post-find-leads-filter-scout",
729
731
  "inputs": [
730
732
  "campaignId",
731
733
  "campaignBrief",
@@ -734,9 +736,16 @@
734
736
  "reviewBatchRowIds/hash",
735
737
  "filterChoice"
736
738
  ],
737
- "stateSource": "CampaignOffer and workflow table rows",
738
- "debugFilesOptionalOnly": true,
739
- "messageDraftRule": "reuse or join the Message Draft Builder branch that started immediately after confirm_lead_list; do not start first-time message drafting here unless the earlier branch failed to start"
739
+ "stateSource": "live campaign/table",
740
+ "debugFilesOptionalOnly": true
741
+ },
742
+ {
743
+ "action": "launch_message_draft_builder_after_filter_decision",
744
+ "mode": "parallel_when_host_supports_subagents",
745
+ "target": "post-find-leads-message-scout",
746
+ "when": "filters_enabled",
747
+ "doesNotQueueCells": true,
748
+ "customerNarration": "Say message agent is drafting."
740
749
  },
741
750
  {
742
751
  "action": "save_filter_rubrics_to_campaign",
@@ -793,10 +802,13 @@
793
802
  "hardRules": [
794
803
  "after_save_rubrics_currentStep_must_be_apply-icp-rubric",
795
804
  "do_not_move_browser_to_messages_until_filter_leads_step_is_current_or_filters_are_explicitly_skipped",
796
- "message_draft_builder_start_is_not_deferred_until_filters"
805
+ "no_post_lead_worker_or_deep_prompt_before_filter_choice",
806
+ "lead_fit_builder_starts_only_after_filters_enabled",
807
+ "msg_draft_after_filter_choice",
808
+ "msg_draft_no_cells"
797
809
  ],
798
810
  "transitions": {
799
- "post_lead_workstreams_ready": "message-review",
811
+ "post_lead_workstreams_ready": "message-generation",
800
812
  "revise_leads": "find-leads",
801
813
  "revise_rubric": "filter-rubric",
802
814
  "revise_messaging": "message-generation",
@@ -865,14 +877,23 @@
865
877
  "id": "message-generation",
866
878
  "label": "Message generation",
867
879
  "onEnter": [
880
+ {
881
+ "action": "set_message_review_visible_step_by_filter_choice",
882
+ "tool": "update_campaign",
883
+ "branchRules": [
884
+ "yes: currentStep=apply-icp-rubric; wait on Filter Leads",
885
+ "no: currentStep=messages; message review"
886
+ ],
887
+ "watchNarration.stage": "fit-message"
888
+ },
868
889
  {
869
890
  "action": "run_or_reconcile_message_draft_builder",
870
891
  "target": "post-find-leads-message-scout",
871
892
  "toolCallRequiredBeforeDraft": [
872
893
  "get_subskill_prompt({ subskillName: \"generate-messages\", offset, limit }) until hasMore=false",
873
- "for approval-only parent-thread review, use get_subskill_asset({ subskillName: \"create-campaign-v2\", assetPath: \"references/message-review-safety-gate.md\" }) instead of loading generate-messages"
894
+ "parent approval uses references/message-review-safety-gate.md only"
874
895
  ],
875
- "stateSource": "campaignBrief, selected source state, selectedLeadListId, workflowTableId, bounded review-batch row ids/hash",
896
+ "stateSource": "campaignBrief, source, selectedLeadListId, workflowTableId, review-batch row ids/hash",
876
897
  "outputState": "messageDraftRecommendation"
877
898
  }
878
899
  ],
@@ -887,11 +908,12 @@
887
908
  "get_subskill_asset",
888
909
  "get_campaign",
889
910
  "get_rows_minimal",
911
+ "update_campaign",
890
912
  "AskUserQuestion",
891
913
  "request_user_input"
892
914
  ],
893
915
  "toolRules": [
894
- "Before message drafting, the Message Draft Builder branch loads the full get_subskill_prompt({ subskillName: \"generate-messages\" }) prompt and drafts from campaignBrief, selected source state, selectedLeadListId, workflowTableId, and imported review-batch rows. For approval-only parent-thread template review, load references/message-review-safety-gate.md and do not load the full generate-messages prompt.",
916
+ "Message Draft Builder loads full get_subskill_prompt({ subskillName: \"generate-messages\" }) from live state. Parent approval uses message-review-safety-gate only.",
895
917
  "Do not use brief.md, lead-review.md, or lead-sample.json as required live state; those files are optional debug context only.",
896
918
  "The compact messageDraftRecommendation must return templateRecommendation, tokenFillRules, renderedSample, concerns, status, basisToken, outputAt, outputHash, and error or retry detail.",
897
919
  "If campaign/source/table/review-batch basis does not match, classify the output stale or blocked."
@@ -902,7 +924,6 @@
902
924
  "save_rubrics",
903
925
  "import_leads",
904
926
  "confirm_lead_list",
905
- "update_campaign",
906
927
  "queue_cells",
907
928
  "start_campaign",
908
929
  "generate_messages"
@@ -106,7 +106,7 @@ fills the source lead list; it does **not** clone rows into the campaign table:
106
106
  ```text
107
107
  import_leads({
108
108
  campaignOfferId,
109
- targetLeadCount: <sourceCandidateTarget; provider default>,
109
+ targetLeadCount: <sourceCandidateTarget from approved good-fit math>,
110
110
  // Signal Discovery only:
111
111
  targetEngagerCount: <ceil(targetGoodFitLeads / sampledFitRateAfterCleanup)>,
112
112
  maxPostsToScrape: <postsNeeded from approved math>
@@ -114,9 +114,15 @@ import_leads({
114
114
  ```
115
115
 
116
116
  Provider is inherited from the selected source decision (not re-selected here)
117
- and should already be saved on the campaign before import. Response returns
118
- `{ imported, skipped, duplicates }` surface all three to the escalation logic
119
- so dedup ratios are visible.
117
+ and should already be saved on the campaign before import. For Sales Nav and
118
+ Prospeo, `<sourceCandidateTarget>` is not the 25-row review batch. It is the
119
+ source-list export/materialization count from the approved source math:
120
+ `min(rawResultCount, providerMax, ceil(targetGoodFitLeads /
121
+ projectedFitRateAfterCleanup))`. If projected good fits remain below the target
122
+ (often about 150+ usable prospects unless the campaign/source defaults specify
123
+ otherwise), return to find-leads and refine filters before import. Response
124
+ returns `{ imported, skipped, duplicates }` — surface all three to the
125
+ escalation logic so dedup ratios are visible.
120
126
 
121
127
  For Signal Discovery, do not scrape every currently selected/promoted sample
122
128
  post by default. Before `import_leads`, reconcile selected posts with the
@@ -127,9 +133,11 @@ rate with a conservative cleanup factor, cap the source candidates at the
127
133
  approved provider limit, and select only enough posts to reach that engager
128
134
  count. The planning floor is 10% projected fit after cleanup; if Signal
129
135
  Discovery falls below that floor, do not import the source list. Route back to
130
- find-leads and move to Sales Nav recent activity instead. The subsequent
131
- `confirm_lead_list` call still uses `targetLeadCount: <importLimit>` so only the
132
- bounded review batch enters the campaign table.
136
+ find-leads and move to Sales Nav recent activity instead. After the scrape,
137
+ `wait_for_lead_list_ready` must clear the approved source-candidate target; if
138
+ it reports `source_under_capacity`, do not call `confirm_lead_list`. The
139
+ subsequent `confirm_lead_list` call still uses `targetLeadCount: <importLimit>`
140
+ so only the bounded review batch enters the campaign table.
133
141
 
134
142
  For supplied direct lists, `confirm_lead_list` must receive
135
143
  `targetLeadCount: <importLimit>` or explicit `sourceRowIds` so a 100-row source
@@ -194,10 +194,10 @@ After review batch import:
194
194
  ```json
195
195
  {
196
196
  "stage": "fit-message",
197
- "headline": "I recommend adding filters",
198
- "visibleState": "The first review batch is in the campaign. The visible sample looks mixed enough that filters should be added before message review.",
199
- "agentIntent": "Codex is asking whether you want to further filter these leads before message review. Skip filters only if the visible rows already look clean.",
200
- "nextAction": "Choose filters or skip",
197
+ "headline": "Filtering may not be needed",
198
+ "visibleState": "25 review leads are in the campaign table from 181 source candidates. Sample read: 23/25 look like senior target-role fits; 2 need cleanup or manual review. The browser is showing the filter-choice screen.",
199
+ "agentIntent": "Codex is not recommending filters because the sample already looks clean. Fit examples: Dave Kranowitz (Chief Revenue Officer); Marie Didominica (Head of Growth Marketing). Add filters only for a narrow exclusion.",
200
+ "nextAction": "Skip filters or add a narrow cleanup rule",
201
201
  "workerStatuses": {
202
202
  "leadFitBuilder": "idle",
203
203
  "messageDraftBuilder": "running"
@@ -206,11 +206,13 @@ After review batch import:
206
206
  ```
207
207
 
208
208
  Use this after the selected review rows are present and before filters are
209
- saved. This is add-filters intent, not active filtering. Recommend adding
210
- filters when the sample is mixed/noisy, tell the user to Choose filters or skip,
211
- and do not say filtering the batch before rubrics and message approval are
212
- saved. The Message Draft Builder should start immediately after the bounded
213
- review batch exists; mark it running only when that branch actually started.
209
+ saved. The filter recommendation must be row-specific: say why filters are
210
+ recommended from the sample counts and examples, or say filtering may not be
211
+ needed when the visible review rows already look clean. This is a user decision
212
+ gate, not active filtering; do not say filtering the batch before rubrics and
213
+ message approval are saved. The Message Draft Builder should start immediately
214
+ after the bounded review batch exists; mark it running only when that branch
215
+ actually started.
214
216
  When the user chooses filters, immediately persist `enableICPFilters: true` and
215
217
  move to `create-icp-rubric` so the watched app shows Filter Rules while Codex
216
218
  defines the rules in chat. After `save_rubrics`, move to `apply-icp-rubric`
@@ -378,7 +378,14 @@ search_apollo({
378
378
 
379
379
  ### ABM / Domain List Targeting
380
380
 
381
- For account-based targeting, use `q_organization_domains_list` to search specific companies:
381
+ For campaign routing, supplied company-domain lists should go to Prospeo first
382
+ using `load_csv_domains` or `save_domain_filters`, then `domainFilterId`.
383
+ Apollo still supports `q_organization_domains_list` as a secondary/legacy
384
+ capability when the user explicitly chooses Apollo or needs an Apollo-only
385
+ filter such as a technographic constraint.
386
+
387
+ If Apollo is explicitly selected for account-based targeting, use
388
+ `q_organization_domains_list` to search specific companies:
382
389
 
383
390
  ```json
384
391
  search_apollo({
@@ -62,7 +62,7 @@ search_prospeo({
62
62
  - Pass `searchId` on subsequent pages to paginate.
63
63
  - Use `import_leads` with `provider: \"prospeo\"` and the `searchId` to create a lead list and start import.
64
64
  - **IMPORTANT:** If `import_leads` returns `needsModeSelection: true`, use `AskUserQuestion` to ask "add to existing leads or replace?" Do NOT assume.
65
- - Default source target is 300+ good-fit leads, capped at 2,500 source candidates for now.
65
+ - Default source target is about 150 good-fit leads, capped at 2,500 source candidates for now.
66
66
  - Apply the campaign source planning floor: the sampled/projected good-fit rate
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
@@ -95,6 +95,11 @@ Prospeo filters are split into person vs company. Most filters use `include` / `
95
95
 
96
96
  Preference rules:
97
97
 
98
+ - For hiring-led campaigns, use `company_job_posting_hiring_for` to target the
99
+ open-role themes and `company_job_posting_quantity` when the campaign needs
100
+ an active hiring floor. Pair those company hiring filters with buyer/referrer
101
+ person filters such as founders, GTM leaders, talent leaders, or revenue
102
+ owners.
98
103
  - For ABM lists, use `load_csv_domains` + `domainFilterId` when the accounts are already in a CSV file on disk.
99
104
  - For pasted/raw domain lists, use `save_domain_filters` + `domainFilterId` instead of inline domains or `company.websites.include`.
100
105
  - If user input starts as company names, resolve names to domains first, then use `save_domain_filters`.
@@ -167,6 +172,11 @@ search_prospeo({
167
172
 
168
173
  ## When to Use Prospeo
169
174
 
175
+ - **Hiring-led targeting**: Find companies hiring for specific roles with
176
+ `company_job_posting_hiring_for` and `company_job_posting_quantity`, then
177
+ identify reachable buyer/referrer contacts at those companies
178
+ - **Account/domain targeting**: Use `domainFilterId` from `load_csv_domains` or
179
+ `save_domain_filters` for ABM searches
170
180
  - **Email Finding**: Get verified work emails from LinkedIn URLs
171
181
  - **Lead Enrichment**: Add company data, job history, and contact info to leads
172
182
  - **Bulk Operations**: Enrich up to 100 leads at once
@@ -387,7 +387,7 @@ User: "Save it"
387
387
  <limits>
388
388
  - 25 results per page
389
389
  - Maximum 100 pages (2,500 leads)
390
- - Default source target: 300+ good-fit leads, capped at 2,500 source
390
+ - Default source target: about 150 good-fit leads, capped at 2,500 source
391
391
  candidates for now
392
392
  - Maximum 5 search calls per session
393
393
  - If user needs more than 2,500: explain limit, suggest splitting by region
@@ -459,6 +459,9 @@ targetLeadCount, targetEngagerCount, maxPostsToScrape })` for the approved
459
459
  source-capacity plan without asking for another yes/no gate. Then
460
460
  `confirm_lead_list` imports only the bounded review batch into the campaign
461
461
  table. Do not confuse the source-candidate target with the review-batch size.
462
+ If the completed source scrape comes back below the approved source-candidate
463
+ target, do not call `confirm_lead_list`; select more posts, rerun source
464
+ discovery, or move to Sales Nav.
462
465
 
463
466
  The promotion/select step is required campaign state. Use post IDs from the
464
467
  current campaign-scoped search result, not stale IDs copied from a source review