@sellable/mcp 0.1.143 → 0.1.145

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 (34) hide show
  1. package/README.md +19 -6
  2. package/agents/post-find-leads-message-scout.md +44 -0
  3. package/agents/registry.json +2 -2
  4. package/agents/source-scout-linkedin-engagement.md +4 -3
  5. package/agents/source-scout-prospeo-contact.md +1 -1
  6. package/agents/source-scout-sales-nav.md +3 -2
  7. package/dist/index-dev.js +0 -0
  8. package/dist/index.js +0 -0
  9. package/dist/tools/leads.js +168 -14
  10. package/dist/tools/processing.d.ts +1 -0
  11. package/dist/tools/prompts.js +3 -3
  12. package/dist/tools/rubrics.js +14 -9
  13. package/package.json +1 -1
  14. package/skills/create-campaign/SKILL.md +55 -34
  15. package/skills/create-campaign-v2/SKILL.md +59 -9
  16. package/skills/create-campaign-v2/SOUL.md +20 -12
  17. package/skills/create-campaign-v2/core/auto-execute.README.md +4 -4
  18. package/skills/create-campaign-v2/core/auto-execute.yaml +4 -4
  19. package/skills/create-campaign-v2/core/flow.v2.json +55 -19
  20. package/skills/create-campaign-v2/references/approval-gate-framing.md +1 -1
  21. package/skills/create-campaign-v2/references/filter-leads.md +42 -0
  22. package/skills/create-campaign-v2/references/final-handoff-contract.md +5 -5
  23. package/skills/create-campaign-v2/references/message-review-safety-gate.md +88 -13
  24. package/skills/create-campaign-v2/references/sample-validation-loop.md +18 -15
  25. package/skills/create-campaign-v2/references/step-13-import-leads.md +9 -6
  26. package/skills/create-campaign-v2/references/step-15-re-cascade.md +2 -3
  27. package/skills/create-campaign-v2/references/watch-guide-narration.md +39 -24
  28. package/skills/create-campaign-v2/references/watch-link-handoff.md +1 -1
  29. package/skills/create-campaign-v2-tail/SKILL.md +26 -13
  30. package/skills/load-voice/SKILL.md +129 -0
  31. package/skills/providers/prospeo.md +2 -1
  32. package/skills/providers/sales-nav.md +4 -2
  33. package/skills/providers/signal-discovery.md +12 -10
  34. package/skills/research/config.json +9 -0
@@ -86,7 +86,7 @@ or tool discovery. Start in product language:
86
86
  ```text
87
87
  I’ll help you launch this as a Sellable campaign. First I’ll resolve the
88
88
  client/company this campaign is for, then I’ll turn that into a campaign brief
89
- before any leads are imported or anything can send.
89
+ before we move into lead sourcing.
90
90
  ```
91
91
 
92
92
  If a linked/local skill file is stale or missing, silently use the installed
@@ -102,8 +102,14 @@ clear business decisions, tradeoffs, and approval gates. Use product language:
102
102
  - "a couple setup choices", not `request_user_input`
103
103
  - "campaign brief", not prompt artifact
104
104
  - "lead source", not provider internals unless comparing source options
105
- - "I can create a draft shell for you to watch, but no leads import and nothing
106
- sends until you approve", not mutation jargon
105
+ - "I can create a draft shell for you to watch with approval gates before
106
+ sourcing", not mutation jargon
107
+
108
+ Approval and safety copy should be tasteful. State what the current approval
109
+ covers once, in one short sentence, then move on. Do not append repeated
110
+ "nothing starts / no leads import / no sending" disclaimers to routine progress
111
+ updates. Use positive gate language like "Next gate: selected-post scrape" or
112
+ "Approval covers scouting/search only" instead of long negative lists.
107
113
 
108
114
  When explaining lead-source decisions, show the concrete counts behind the
109
115
  logic: lanes searched, timeframe, raw result counts, finalist posts or preview
@@ -127,7 +133,7 @@ authorizes scouting/search only. The gate should say:
127
133
  - why that lane fits the buyer, offer, and likely public activity
128
134
  - what will be tested next
129
135
  - the fallback lane if relevant posts or ICP engagement look thin
130
- - that approval authorizes scouting/search only, not lead import or sending
136
+ - what approval covers in one concise line
131
137
 
132
138
  Do not surface blanket source heuristics as product copy. Make the
133
139
  recommendation specific to the campaign. If Signal Discovery is recommended,
@@ -142,6 +148,21 @@ Signal Discovery, name how many selected posts will be scraped, the target
142
148
  engager/source-candidate volume, and the bounded review-batch size. For Sales
143
149
  Nav or Prospeo, name the specific approved import lane. Do not call
144
150
  `import_leads` or `confirm_lead_list` until this second approval is granted.
151
+ For Signal Discovery, the customer-facing approval card must use the exact
152
+ action shape "Approve scraping N Signal Discovery posts?" and the chat summary
153
+ should be a compact `## Source Recommendation` block with:
154
+
155
+ - good-fit target: about 150 prospects after cleanup, enrichment, and filters
156
+ - source-candidate plan: about 1,000 raw engagers using a conservative 15%
157
+ fit-rate assumption unless sampled data supports a different number
158
+ - review checkpoint: import the first 25 leads for fit and message review
159
+ - a selected-post table with post author/topic, why it fits, and visible
160
+ engagement
161
+ - total visible pool and estimated good-fit pool
162
+ - first pass: build the source list, then import only the review
163
+ batch
164
+ - fallback: switch to Sales Nav recent activity if the review batch is
165
+ vendor-heavy, agency-heavy, or off-ICP
145
166
 
146
167
  When the user has not supplied a source and multiple source angles are viable,
147
168
  scout those angles as independent branches when the host can actually do it:
@@ -168,19 +189,17 @@ which posts are being sampled in the watched app. The watch guide should say
168
189
  that we are pulling sample engagers from these posts to confirm the ICP is
169
190
  actually engaging and the source is viable.
170
191
 
171
- After find-leads returns a lead source and the user approves it, use the same
172
- registry pattern for the two post-lead branches. The create-campaign-v2 subskill
173
- calls `get_post_find_leads_scout_registry`, then launches the returned
174
- filter-leads scout and message-generation scout together when real subagents are
175
- available and the current session exposes the returned names. Message
176
- generation is the provisional Message Draft Builder: it may start after the
177
- review batch exists, including while the user is on filter choice, but workflow
178
- cell execution must wait. After rubrics are saved, do not queue enrichment,
179
- filtering, or Generate Message cells until the user approves the message
180
- template. AI Generated is an explicit opt-out that cancels or ignores the
181
- background template draft. If the post-lead agents are absent, the main thread
182
- still orchestrates the same branches from the compact context with MCP
183
- tools/assets.
192
+ After the bounded review batch exists, use the same registry pattern for
193
+ post-lead work. The create-campaign-v2 subskill calls
194
+ `get_post_find_leads_scout_registry`, then launches the returned
195
+ message-generation scout immediately when real subagents are available and the
196
+ current session exposes the returned name. If the user chooses filters, launch
197
+ the filter-leads scout then and join it with the already-running or completed
198
+ message draft before message review. Workflow cell execution still waits for
199
+ filter and template approval. AI Generated is an explicit opt-out that cancels
200
+ or ignores the background template draft. If the post-lead agents are absent,
201
+ the main thread still orchestrates the same branches from the compact context
202
+ with MCP tools/assets.
184
203
 
185
204
  Use rendered Markdown for user review surfaces, not fenced code blocks. Keep
186
205
  lines short, use indexed section labels and bullets, and translate internal
@@ -233,7 +252,7 @@ After every `update_campaign({ campaignId, currentStep })`, use
233
252
  `get_campaign_navigation_state` when available as a compact orientation check:
234
253
  match the saved campaign state to the expected watch-link step, explain the
235
254
  current state in one sentence, and only then continue. Sender selection belongs
236
- at Settings after message approval and 15-row validation. After message
255
+ at Settings after message approval and review-batch validation. After message
237
256
  validation, use Settings to help the user connect or select a LinkedIn sender.
238
257
  Explain Slack reply review before launch. After sender selection, attach the
239
258
  recommended sequence and move the watched UI to Send. Do not start the campaign
@@ -412,7 +431,7 @@ First I’ll resolve the client/company this campaign is for. I’ll use that
412
431
  context to choose the target, offer, proof, and lead source.
413
432
 
414
433
  Then I’ll turn that into a campaign brief for you to approve before any leads
415
- are imported or anything can send.
434
+ are sourced.
416
435
  ```
417
436
 
418
437
  Do not silently ask Codex intake or approval questions as plain chat when
@@ -596,9 +615,9 @@ updates.
596
615
  until `hasMore=false`. The create-campaign message-review safety gate is a
597
616
  supplemental approval checklist, not a replacement for the long prompt. Use
598
617
  campaign state, campaign brief content, selected source state, and imported
599
- review-batch rows as the source of truth; do not read stale local markdown,
600
- inspect the database directly, or synthesize local validation artifacts from
601
- general knowledge.
618
+ review-batch rows as the source of truth; do not read stale local markdown
619
+ such as `message-validation.md`, inspect the database directly, or synthesize
620
+ local validation artifacts from general knowledge.
602
621
  5. Create the campaign shell early with the v1 brief so the user can open the
603
622
  watch link and see useful setup state immediately. Import only the first
604
623
  bounded review batch after the source is attached to the campaign; do not
@@ -609,9 +628,11 @@ updates.
609
628
  call `mcp__sellable__update_campaign({ campaignId, enableICPFilters: true, currentStep: "create-icp-rubric", watchNarration })`
610
629
  so the watched app moves to Filter Rules while rubrics are drafted/saved.
611
630
  After rubrics save, move the watched app to `apply-icp-rubric` / Filter
612
- Leads and say the fit rules are saved; approve the message template next;
613
- after approval, queue the bounded review-batch
614
- `enrichCellId` cells to kick off enrichment/filtering.
631
+ Leads and say the fit rules are saved; approve the message template next
632
+ while the browser stays on Filter Leads. After approval, save the template
633
+ to the campaign brief, then queue the bounded review-batch `enrichCellId`
634
+ cells to kick off enrichment/filtering. Move to Messages only after at
635
+ least one review row passes and Generate Message cells are running or ready.
615
636
  Product Generate Message cells must not run from the background template
616
637
  path before that template/token approval.
617
638
  Do not ask the user to approve the brief before shell creation unless they
@@ -620,15 +641,15 @@ updates.
620
641
  `mcp__sellable__update_campaign({ campaignId, currentStep })` before major
621
642
  visible work so the user can watch progress in the app: `create-offer` for
622
643
  the brief, `pick-provider` or the selected provider step while sourcing,
623
- `filter-choice` after the 15-row review batch, `create-icp-rubric` as soon
624
- as filters are approved, `apply-icp-rubric` after rubrics save, `messages`
625
- for the Use Template / AI Generated mode
626
- choice, `auto-execute-messaging` for approved
627
- message work or the product's AI-generated path, `awaiting-user-greenlight`
628
- for the final handoff, `settings` for sender selection, `sequence` after
629
- sender attach, and `send` once the recommended sequence is attached.
630
- `validate-sample` is recovery/legacy only if reached. Do not advance the
631
- step backward.
644
+ `filter-choice` after the review batch, `create-icp-rubric` as soon
645
+ as filters are approved, `apply-icp-rubric` after rubrics save and while
646
+ waiting for message-template approval, `validate-sample` while the approved
647
+ template unlocks bounded enrichment/filter scoring on Filter Leads,
648
+ `auto-execute-messaging` after at least one row passes and review-batch
649
+ messages are being generated or reviewed, `awaiting-user-greenlight` only
650
+ after generated review-batch messages are approved, `settings` for sender
651
+ selection, `sequence` after sender attach, and `send` once the recommended
652
+ sequence is attached. Do not advance the step backward.
632
653
  7. Keep `selectedLeadListId` as the source list and `workflowTableId` as the
633
654
  campaign table. Do not use disk files as the post-mint source of truth.
634
655
  8. Do not ask the user to run another command.
@@ -47,8 +47,11 @@ for debug output.
47
47
  rows.
48
48
  11. Review and approve/revise the message.
49
49
  12. Sync the approved template into the campaign brief.
50
- 13. Validate the bounded review batch, then move to Settings, sender, sequence,
51
- and explicit launch greenlight.
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, generate and
53
+ review bounded messages, then hand off to Settings, sender, sequence, and
54
+ explicit launch greenlight.
52
55
 
53
56
  There is no normal approval-packet, commit-gate, atomic-mint, or local
54
57
  artifact-validation step. Those belong only to legacy validation/rehearsal
@@ -151,10 +154,48 @@ After scouting, show a second approval gate for the concrete source action. For
151
154
  Signal Discovery, this gate must say how many selected posts will be scraped,
152
155
  the target engager/source-candidate volume, the bounded campaign review-batch
153
156
  size, the cleanup risk, and the fallback if the selected posts look wrong. The
154
- approval label should describe the action, such as "Scrape 2 selected posts for
155
- the bounded review batch." For Sales Nav or Prospeo, the label should name the
156
- specific search/import lane. Do not call `import_leads` or `confirm_lead_list`
157
- until this second source-action approval is granted.
157
+ approval label must describe the action with the count, such as "Approve
158
+ scraping 3 Signal Discovery posts?" For Sales Nav or Prospeo, the label should
159
+ name the specific search/import lane. Do not call `import_leads` or
160
+ `confirm_lead_list` until this second source-action approval is granted.
161
+
162
+ For Signal Discovery, use this compact source-action approval shape after
163
+ selected posts exist:
164
+
165
+ ```markdown
166
+ ## Source Recommendation
167
+
168
+ Use Signal Discovery first.
169
+
170
+ **Good-fit target:** ~150 prospects after cleanup, enrichment, and filters<br>
171
+ **Source-candidate plan:** scrape ~1,000 raw engagers using a conservative 15% fit-rate assumption<br>
172
+ **Review checkpoint:** import the first 25 leads into the campaign for fit and message review before scaling<br>
173
+
174
+ ### Selected posts
175
+
176
+ | Post | Why it fits | Visible engagement |
177
+ | ---------------- | ----------------------------------------------- | -----------------: |
178
+ | Dylan Power | Claude outbound system | ~1,571 |
179
+ | Fivos Aresti | Replacing Clay outbound with Claude Code | ~734 |
180
+ | Divyanshi Sharma | LinkedIn lead-gen system built with Claude Code | ~508 |
181
+
182
+ **Total visible pool:** ~2,813 engagers<br>
183
+ **Estimated good-fit pool at 15%:** ~420 prospects before dedupe/risk cleanup
184
+
185
+ ### Recommendation
186
+
187
+ Approve scraping these 3 posts.
188
+
189
+ This gives enough volume to work toward ~150 good-fit prospects, while
190
+ keeping the source tied to people already engaging with Claude Code outbound /
191
+ AI-native sales workflows.
192
+
193
+ **First pass:** build the source list, then import only the 25-lead review
194
+ batch so we can inspect fit and messages before scaling.
195
+
196
+ **Fallback:** if the review batch is too vendor-heavy, agency-heavy, or
197
+ off-ICP, switch to Sales Nav recent activity.
198
+ ```
158
199
 
159
200
  A source recommendation must show concrete evidence: source lane, filters or
160
201
  recipe, raw volume, sample size, sampled fits as n/N plus percentage/range,
@@ -169,8 +210,15 @@ customer-facing source-choice labels.
169
210
 
170
211
  After `confirm_lead_list` imports a non-empty bounded review batch and
171
212
  `get_rows_minimal({ tableId: workflowTableId })` proves rows exist, call
172
- `get_post_find_leads_scout_registry`. The filter and message branches use live
173
- CampaignOffer/source/table state as the source of truth. Debug markdown/json
213
+ `get_post_find_leads_scout_registry` and start the Message Draft Builder branch
214
+ immediately when the current host exposes that returned agent. Do this before
215
+ asking the filter-choice question. If no real background branch can start, say
216
+ the real sequence and do not claim background drafting is running.
217
+
218
+ The message branch uses live CampaignOffer/source/table state as the source of
219
+ truth and may draft while the user is choosing filters. It does not write
220
+ message cells, enrich rows, attach sequences, or unlock Settings. The Lead Fit
221
+ Builder branch starts only after the user chooses filters. Debug markdown/json
174
222
  artifacts are optional only.
175
223
 
176
224
  When the user chooses filters, immediately call
@@ -198,7 +246,9 @@ get_subskill_asset({ subskillName: "create-campaign-v2", assetPath: "references/
198
246
  ```
199
247
 
200
248
  Do not load the full `generate-messages` prompt in the create-campaign parent
201
- thread unless you are executing the parent-thread fallback for that branch.
249
+ thread unless you are executing the parent-thread fallback for the actual
250
+ message-draft branch. Parent-thread template approval uses only the compact
251
+ message-review safety gate.
202
252
 
203
253
  ## Hard Gates
204
254
 
@@ -35,7 +35,7 @@ tell them what they will see next.
35
35
  is missing.
36
36
  - "lead source" beats provider internals unless comparing options.
37
37
  - "I’ll create the campaign shell with the brief so you can watch it fill in,
38
- but no leads import and nothing sends yet" beats mutation jargon.
38
+ with approval gates before sourcing" beats mutation jargon.
39
39
  - "I’m turning this into a brief now" beats "I’m persisting the draft."
40
40
  - "Sorry, this is taking a little longer than expected" is appropriate when a
41
41
  step overruns its estimate. Do not over-apologize; one calm acknowledgment is
@@ -148,9 +148,9 @@ unless the user asks for them.
148
148
  Good opening:
149
149
 
150
150
  ```text
151
- I’ll help you launch this as a Sellable campaign. First I’ll resolve the
152
- client/company this campaign is for, then I’ll turn that into a campaign brief
153
- before any leads are imported or anything can send.
151
+ I’ll help you launch this as a Sellable campaign. First I’ll confirm who we’re
152
+ sending from and which company this is for, then I’ll turn that into a campaign
153
+ brief before lead sourcing or anything can send.
154
154
  ```
155
155
 
156
156
  Good identity setup:
@@ -236,6 +236,13 @@ source. That approval only authorizes scouting/search. Second, after the
236
236
  source evidence exists, show counts, samples, fit math, cleanup risk, and ask
237
237
  for source approval before import.
238
238
 
239
+ For Signal Discovery, the second gate is not "approve source" in the abstract.
240
+ It is a concrete scrape approval: show a compact `## Source Recommendation`
241
+ with the ~150 good-fit prospect goal, 15% raw-engager assumption, selected-post
242
+ table, total visible pool, estimated good-fit pool, first-pass review
243
+ batch, and fallback. The approval question should be "Approve scraping N Signal
244
+ Discovery posts?"
245
+
239
246
  ## Parallelism + Naming
240
247
 
241
248
  Source selection is sequential by default. Start with the first recommended
@@ -257,14 +264,15 @@ scout loads only its matching provider prompt. If source work is sequential,
257
264
  keep the output numeric but do not claim the source scout was parallel or
258
265
  surface install status to the customer.
259
266
 
260
- For post-lead work, call `get_post_find_leads_scout_registry` after source
261
- approval and use the returned canonical `name` values. Launch both returned
262
- scouts in the same assistant turn/message when real subagents are available:
263
- `post-find-leads-filter-scout` and `post-find-leads-message-scout`. This is the
264
- same registry pattern as source scouting, but the trigger is approved
265
- source output plus a non-empty bounded review batch. The join gate is live
266
- branch readiness: saved rubrics or a resolved skip-filter choice, plus a message
267
- recommendation grounded in the same campaign/table basis.
267
+ For post-lead work, call `get_post_find_leads_scout_registry` after
268
+ `confirm_lead_list` imports a non-empty bounded review batch and
269
+ `get_rows_minimal` proves rows exist. Start `post-find-leads-message-scout`
270
+ immediately when real subagents are available, before asking the filter-choice
271
+ question. Start `post-find-leads-filter-scout` only after the user chooses
272
+ filters. This is the same registry pattern as source scouting, but the trigger
273
+ for message drafting is review-batch import, not filter approval. The join gate
274
+ is live branch readiness: saved rubrics or a resolved skip-filter choice, plus a
275
+ message recommendation grounded in the same campaign/table basis.
268
276
 
269
277
  Only promise parallel post-lead work when parallel work actually started. If the
270
278
  host cannot or should not launch background branches, say the real sequence:
@@ -33,16 +33,16 @@ the imported review batch for validation).
33
33
 
34
34
  - **`sampleSize`** — How many rows the validation loop pulls from the
35
35
  imported review batch. In v2 this matches the review-batch cap
36
- (default 15), so the user sees enough real rows to judge the campaign
36
+ (default 25), so the user sees enough real rows to judge the campaign
37
37
  without spending credits on hundreds more.
38
38
  - **`minProjectedPass`** — Passing-message floor required before handoff.
39
- The default requires 3 passing examples from the 15-row review batch.
39
+ The default requires 5 passing examples from the 25-row review batch.
40
40
  Math:
41
41
  ```text
42
42
  projectedPass = round(passInSample / sampleSize * importLimit)
43
43
  ```
44
- With defaults (sampleSize=15, importLimit=15), `projectedPass` equals
45
- the actual review-batch pass count. 3 passing rows is exactly at the
44
+ With defaults (sampleSize=25, importLimit=25), `projectedPass` equals
45
+ the actual review-batch pass count. 5 passing rows is exactly at the
46
46
  floor.
47
47
  - **`maxRevisionRounds`** — Hard cap before escalating to the user. A
48
48
  revision round is one full sample pass that triggered brief revision
@@ -17,7 +17,7 @@ import:
17
17
  # Initial review batch imported in Step 13 before the sample validation
18
18
  # loop. Import + enrichment must never exceed this cap before the user
19
19
  # reviews the sample and explicitly asks to expand.
20
- importLimit: 15
20
+ importLimit: 25
21
21
  # Provider is inherited from the campaign-attached source association created
22
22
  # during find-leads. Step 13 may re-run provider preflight in memory, but it
23
23
  # does not choose a new source.
@@ -27,11 +27,11 @@ sample:
27
27
  # Rows pulled from the imported cohort for the validation loop. In v2 this
28
28
  # equals the review-batch cap so the user sees a focused first test batch
29
29
  # without spending credits on hundreds of rows.
30
- sampleSize: 15
30
+ sampleSize: 25
31
31
  # Projected first-batch passing count required to proceed to sample
32
32
  # messaging. This is not approval to scale the full source list.
33
33
  # projectedPass = round(passInSample / sampleSize * importLimit).
34
- minProjectedPass: 3
34
+ minProjectedPass: 5
35
35
  # Hard cap on revision loops before escalating to the user. On a stale
36
36
  # resume the counter does NOT reset — the 3-round cap holds across
37
37
  # sessions.
@@ -106,7 +106,7 @@ handoff:
106
106
  # Orientation surfaced in Step 16 ("awaiting-user-greenlight") along with
107
107
  # the watch link. Keep this short and user-facing.
108
108
  orientation: >-
109
- Review the first 15 enriched leads and messages. If they look good,
109
+ Review the first 25 enriched leads and messages. If they look good,
110
110
  attach a sender in Settings, accept the recommended sequence, and start
111
111
  the campaign without spending credits on more leads first.
112
112
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "v2.1-compact",
3
3
  "workflow": "create-campaign-v2",
4
- "principle": "CampaignOffer state and the watch link are canonical from the first brief onward. The active customer path is shell-first and state-first: create the watchable campaign shell with the brief, attach source/search state to that CampaignOffer, import one bounded review batch, persist rubrics and approved message template, validate the review batch, then hand off to Settings, sequence, and explicit start.",
4
+ "principle": "CampaignOffer state and the watch link are canonical from the first brief onward. The active customer path is shell-first and state-first: create the watchable campaign shell with the brief, attach source/search state to that CampaignOffer, import one bounded review batch, persist rubrics, wait on Filter Leads for approved message-template review, save the approved template, validate the bounded review batch, generate and review bounded messages, then hand off to Settings, sequence, and explicit start.",
5
5
  "normalCustomerPath": "Use campaign state, MCP tool responses, and concise watchNarration. Do not create, read, link, or surface local draft files in normal customer runs.",
6
6
  "legacyCompatibility": {
7
7
  "validationSubskill": "create-campaign-v2-validation",
@@ -460,6 +460,7 @@
460
460
  "requiredInlineFields": [
461
461
  "primary source and exact filters/recipe",
462
462
  "specific source action awaiting approval",
463
+ "for Signal Discovery: Source Recommendation markdown with ~150 good-fit prospects as the target, source-candidate plan ~1,000 raw engagers at a conservative ~15% fit assumption, review checkpoint size, selected-post table, total visible pool, estimated good-fit pool, first pass, and fallback",
463
464
  "for Signal Discovery: selected post count and target engager/source-candidate volume",
464
465
  "bounded review batch size",
465
466
  "runner-up and why it lost",
@@ -475,13 +476,13 @@
475
476
  "action": "ask_source_review_choice",
476
477
  "uses": "request_user_input",
477
478
  "choices": [
478
- "Scrape selected posts for the bounded review batch",
479
+ "Approve scraping N Signal Discovery posts",
479
480
  "Run the approved source import for the bounded review batch",
480
481
  "Revise source",
481
482
  "Pause here"
482
483
  ],
483
484
  "approvalChoiceLabelsByProvider": {
484
- "signal-discovery": "Scrape selected posts for the bounded review batch",
485
+ "signal-discovery": "Approve scraping {selectedPostCount} Signal Discovery posts?",
485
486
  "sales-nav": "Import the approved Sales Nav review batch",
486
487
  "prospeo": "Import the approved Prospeo review batch"
487
488
  }
@@ -540,7 +541,7 @@
540
541
  "importLimit"
541
542
  ],
542
543
  "requiredValues": {
543
- "importLimit": 15
544
+ "importLimit": 25
544
545
  },
545
546
  "modeAddHandshake": {
546
547
  "firstCallReturns": "needsModeSelection when adding to an existing campaign-attached list",
@@ -579,7 +580,18 @@
579
580
  {
580
581
  "action": "launch_message_draft_builder_after_review_batch_import",
581
582
  "tool": "get_post_find_leads_scout_registry",
582
- "requiresNonEmptyRows": true
583
+ "target": "post-find-leads-message-scout",
584
+ "requiresNonEmptyRows": true,
585
+ "mustRunBefore": [
586
+ "filter-choice question",
587
+ "filter approval",
588
+ "save_rubrics"
589
+ ],
590
+ "mode": "background_when_host_supports_subagents",
591
+ "fallback": "if no real background branch can start, say the real sequence and do not claim background drafting is running",
592
+ "toolCallRequiredInBranch": "get_subskill_prompt({ subskillName: \"generate-messages\", offset, limit }) until hasMore=false",
593
+ "runtimeProofTransport": "CampaignOffer.watchNarration.workerDetails.messageDraftBuilder",
594
+ "purpose": "start the provisional message draft from the imported review batch immediately; do not defer this to filter approval"
583
595
  }
584
596
  ],
585
597
  "requiredCampaignState": [
@@ -702,7 +714,7 @@
702
714
  "purpose": "load canonical post-lead worker names"
703
715
  },
704
716
  {
705
- "action": "launch_or_reuse_post_lead_workstreams",
717
+ "action": "launch_or_reuse_lead_fit_builder_and_existing_message_draft",
706
718
  "mode": "parallel_when_host_supports_subagents",
707
719
  "inputs": [
708
720
  "campaignId",
@@ -713,7 +725,8 @@
713
725
  "filterChoice"
714
726
  ],
715
727
  "stateSource": "CampaignOffer and workflow table rows",
716
- "debugFilesOptionalOnly": true
728
+ "debugFilesOptionalOnly": true,
729
+ "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"
717
730
  },
718
731
  {
719
732
  "action": "save_filter_rubrics_to_campaign",
@@ -727,7 +740,7 @@
727
740
  "requiredSideEffects": {
728
741
  "enableICPFilters": true,
729
742
  "currentStep": "apply-icp-rubric",
730
- "watchNarration.headline": "Filter Leads is ready"
743
+ "watchNarration.headline": "Filter rules saved"
731
744
  }
732
745
  }
733
746
  ],
@@ -769,7 +782,8 @@
769
782
  ],
770
783
  "hardRules": [
771
784
  "after_save_rubrics_currentStep_must_be_apply-icp-rubric",
772
- "do_not_move_browser_to_messages_until_filter_leads_step_is_current_or_filters_are_explicitly_skipped"
785
+ "do_not_move_browser_to_messages_until_filter_leads_step_is_current_or_filters_are_explicitly_skipped",
786
+ "message_draft_builder_start_is_not_deferred_until_filters"
773
787
  ],
774
788
  "transitions": {
775
789
  "post_lead_workstreams_ready": "message-review",
@@ -800,7 +814,7 @@
800
814
  "requiredSideEffects": {
801
815
  "enableICPFilters": true,
802
816
  "currentStep": "apply-icp-rubric",
803
- "watchNarration.headline": "Filter Leads is ready"
817
+ "watchNarration.headline": "Filter rules saved"
804
818
  }
805
819
  }
806
820
  ],
@@ -968,17 +982,26 @@
968
982
  "revise_messaging"
969
983
  ],
970
984
  "transitions": {
971
- "message_approved": "auto-execute-messaging",
985
+ "message_approved": "validate-sample",
972
986
  "revise_messaging": "message-generation"
973
987
  }
974
988
  },
975
989
  {
976
990
  "id": "validate-sample",
977
- "label": "Validate bounded review batch (legacy)",
978
- "currentStepValue": "validate-sample",
979
- "legacyOnly": true,
991
+ "label": "Validate bounded review batch",
992
+ "currentStepValue": "apply-icp-rubric",
980
993
  "reference": "references/sample-validation-loop.md",
994
+ "visibleStepRule": "This is the same Filter Leads screen reached by save_rubrics. Do not route away from or back to Filter Leads on approve-message; save the approved template, refresh watch narration on apply-icp-rubric, then queue the bounded Enrich Prospect cells.",
981
995
  "onEnter": [
996
+ {
997
+ "tool": "update_campaign",
998
+ "requiredValues": {
999
+ "currentStep": "apply-icp-rubric",
1000
+ "watchNarration.stage": "fit-message"
1001
+ },
1002
+ "purpose": "keep the watched UI on Filter Leads while the approved template starts the bounded cascade",
1003
+ "watchNarrationRule": "Say the template is saved and Filter Leads is now running the bounded enrichment and scoring pass."
1004
+ },
982
1005
  {
983
1006
  "tool": "queue_cells",
984
1007
  "purpose": "queue ICP/enrichment cells for the bounded review batch only",
@@ -1121,10 +1144,21 @@
1121
1144
  {
1122
1145
  "tool": "update_campaign",
1123
1146
  "requiredValues": {
1124
- "currentStep": "awaiting-user-greenlight",
1147
+ "currentStep": "auto-execute-messaging",
1125
1148
  "watchNarration.stage": "review-ready"
1126
1149
  },
1127
- "watchNarrationRule": "Say what just happened, that review-batch messages are ready, and that the next action is Settings/sender review."
1150
+ "watchNarrationRule": "Say what just happened, that review-batch messages are ready in Messages, and that the next action is reviewing or approving generated messages before Settings."
1151
+ },
1152
+ {
1153
+ "action": "ask_generated_message_review_choice",
1154
+ "uses": "request_user_input",
1155
+ "choices": [
1156
+ "Approve generated messages",
1157
+ "Revise filters",
1158
+ "Revise message template",
1159
+ "Pause here"
1160
+ ],
1161
+ "rule": "Do not advance to Settings until the generated review-batch messages have been reviewed and approved."
1128
1162
  }
1129
1163
  ],
1130
1164
  "allowedTools": [
@@ -1151,11 +1185,13 @@
1151
1185
  "proposed_token_never_persisted_in_rewrite"
1152
1186
  ],
1153
1187
  "waitFor": [
1154
- "review_batch_ready",
1188
+ "generated_messages_approved",
1155
1189
  "sample_revision_required"
1156
1190
  ],
1157
1191
  "transitions": {
1158
- "review_batch_ready": "awaiting-user-greenlight",
1192
+ "generated_messages_approved": "awaiting-user-greenlight",
1193
+ "revise_filters": "filter-rubric",
1194
+ "revise_messaging": "message-generation",
1159
1195
  "escalation_triggered": "escalation"
1160
1196
  }
1161
1197
  },
@@ -1188,7 +1224,7 @@
1188
1224
  "connect or select a LinkedIn sender",
1189
1225
  "Slack reply review",
1190
1226
  "recommended sequence",
1191
- "nothing starts until the user confirms launch"
1227
+ "final launch confirmation is still ahead"
1192
1228
  ]
1193
1229
  },
1194
1230
  {
@@ -15,7 +15,7 @@ packet.
15
15
 
16
16
  The approval gate used to be the place where the user authorized
17
17
  spend/send-adjacent mutation. It is now compatibility-only. New runs import the
18
- bounded 15-row review batch after source approval, save rubrics and the approved
18
+ bounded review batch after source approval, save rubrics and the approved
19
19
  message template after post-import review, and only then queue the cascade.
20
20
 
21
21
  If `campaign-shell.json` exists, a draft `CampaignOffer` row already exists but
@@ -174,6 +174,14 @@ If more than roughly 20% of the review batch appears to be the forbidden side,
174
174
  classify it as a list/source problem and return `revise-find-leads`; do not
175
175
  hide that problem behind narrow rubrics.
176
176
 
177
+ ## Suppression And Relationship Safety
178
+
179
+ Do not put DNC or one-off relationship-safety notes into production rubrics
180
+ unless the review batch shows that the pattern will leak at meaningful volume
181
+ and normal DNC/domain suppression will not catch it. Former employers, existing
182
+ customers, investors, partner lists, and one-off do-not-contact domains usually
183
+ belong in the recommendation as DNC/suppression instructions outside the rubric JSON.
184
+
177
185
  ## Production Rubric Shape
178
186
 
179
187
  Confirmed rubrics must use the production `LeadScoringRubric` fields exactly:
@@ -265,6 +273,40 @@ Interpretation:
265
273
  - Density dramatically below the band: likely source contamination, ICP drift,
266
274
  or provider-side weakness; investigate before launch.
267
275
 
276
+ ## Post-Filter Signal Enrichment Pass (Sales Nav lane)
277
+
278
+ Run this only for Sales Nav FIT rows when the downstream message step does not
279
+ already have row-level post evidence. In normal campaign-backed runs, use live
280
+ campaign-table row state as the source of truth. In explicit debug/UAT artifact
281
+ flows, append the diagnostic copy back to `lead-sample.json`.
282
+
283
+ This pass exists to protect the Earned-right and Read-as-1:1 substance filters.
284
+ Without row-level posts, message generation is likely to fall back to generic
285
+ category openers or presumed intent instead of evidence the recipient can
286
+ recognize.
287
+
288
+ Contract:
289
+
290
+ - scope: Sales Nav FIT rows only; do not enrich MAYBE or REJECT rows for this
291
+ pass
292
+ - budget cap: top 10 FIT rows by filter score
293
+ - tool: `mcp__sellable__fetch_linkedin_posts`, called per row
294
+ - fetch: most recent 3-5 public posts when available
295
+ - target surface: store each result as `recent_posts[]` entries with
296
+ `{ url, posted_at, excerpt }`; keep `recent_posts: []` for quiet profiles
297
+ - order of operations: run AFTER `lead-filter.md` is written, BEFORE
298
+ `message-validation.md` starts drafting
299
+
300
+ Record enrichment outcome in the filter summary: rows attempted, rows with
301
+ posts, rows with zero public posts, and tool failures. If more than half of the
302
+ attempted rows have zero posts, flag low signal density and tell message
303
+ generation to prefer trigger, peer-observation, or non-post proof instead of a
304
+ post-quote opener.
305
+
306
+ Do not convert "recently posted" or post availability into an ICP fit rubric.
307
+ The posts are message evidence only; buyer qualification still comes from role,
308
+ authority, account fit, capacity, geography, and exclusions.
309
+
268
310
  ## Decision Rules
269
311
 
270
312
  - Use `confirmed` when the source lane is viable and the rubrics are enough to