@sellable/mcp 0.1.116 → 0.1.118

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index-dev.js CHANGED
File without changes
package/dist/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.116",
3
+ "version": "0.1.118",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -165,47 +165,31 @@ linked skill versions, runbooks, npm/package details, repo-local files, VPS or
165
165
  browser automation limitations, or local skill files in normal customer-facing
166
166
  copy.
167
167
 
168
- ## Watch Link Handoff
169
-
170
- When a campaign tool returns `watchUrl`, treat it as a user-opened watch link.
171
- A valid handoff link must be a safe direct
172
- `/campaign-builder/{campaignId}?mode=claude|codex|watch` URL.
173
- `create_campaign.watchUrl`, `create_campaign({ campaignId }).watchUrl`, and
174
- `get_campaign.watchUrl` are all acceptable only when they return that direct
175
- campaign-builder shape, with `workspaceId` used only as a safe routing hint when
176
- needed.
177
-
178
- Do not claim Sellable can force every host to open links in a specific browser.
179
- The host controls link-click behavior. Do not call Chrome, browser automation,
180
- shell `open`, Computer Use, or in-app browser-control tools just because a
181
- watch link exists.
182
-
183
- - In Codex Desktop, clicking a URL can open the Codex in-app browser, but that
184
- browser is only reliable for unauthenticated/public pages. Sellable campaign
185
- watch pages may need a signed-in session. Tell the user to click the link
186
- first; if it lands on sign-up/auth, they should open the same link in their
187
- regular browser to watch real-time updates.
188
- - In Claude Code, provide the link and direct the user to open it in their
189
- browser. If their Claude Code setup opens links in an in-app/preview browser,
190
- that is fine, but do not attempt to open Chrome for them.
191
-
192
- Make the direct watch link easy to copy/open, then continue with explicit
193
- customer-facing campaign progress and `get_campaign_navigation_state`
194
- orientation checks. Use this fallback shape:
168
+ ## Codex Watch Link Handoff
169
+
170
+ When a campaign tool returns `watchUrl`, treat it as a user-opened app link, not
171
+ as permission to drive the browser. A valid handoff link must be a direct
172
+ `/campaign-builder/{campaignId}?mode=claude|codex` URL with the auth token and
173
+ workspace routing needed for auto-login. `create_campaign.watchUrl`,
174
+ `create_campaign({ campaignId }).watchUrl`, and `get_campaign.watchUrl` are all
175
+ acceptable only when they return that direct campaign-builder shape.
176
+
177
+ Never call browser-opening tools, shell `open`, Computer Use, or in-app browser
178
+ automation just because a watch link exists. Print the link and tell the user to
179
+ Command-Enter/click it when they want to watch in the app. Use this shape:
195
180
 
196
181
  ```text
197
- Watch link: [Open campaign]({watchUrl})
182
+ Watch link: {watchUrl}
198
183
 
199
- Click that link to watch the campaign. If it opens in an in-app browser and asks
200
- you to sign in, open the same link in your regular browser so you can watch
201
- real-time updates from your signed-in session. I’ll keep the brief, lead source,
202
- and message-review steps explicit here as I build.
184
+ Command-Enter or click that link to watch the campaign in Sellable. I’ll keep
185
+ the brief, lead source, and message-review steps explicit here as I build.
203
186
  ```
204
187
 
205
- If the user reports that the watch link lands on auth, 404, permission, blank,
206
- or an error state, recover a fresh watch link once with
207
- `create_campaign({ campaignId })` or `get_campaign`, then print the recovered
208
- link. Do not claim the browser was opened, inspected, or synchronized.
188
+ The watch link should auto-login through the token in the URL. If the user says
189
+ the link lands on auth, 404, permission, blank, or a visible error state, recover
190
+ a fresh watch link once with `create_campaign({ campaignId })` or `get_campaign`
191
+ and print that link. Do not claim the browser was opened, inspected, or
192
+ synchronized.
209
193
 
210
194
  Never print a placeholder watch link such as "Open campaign" or "link will
211
195
  update once the shell is created." If the shell is not created yet, call
@@ -214,7 +198,7 @@ and surface the missing watch-link error before lead sourcing.
214
198
 
215
199
  After every `update_campaign({ campaignId, currentStep })`, use
216
200
  `get_campaign_navigation_state` when available as a compact orientation check:
217
- match the expected watch-link step to the saved campaign state, explain the
201
+ match the saved campaign state to the expected watch-link step, explain the
218
202
  current state in one sentence, and only then continue. Sender selection belongs
219
203
  at Settings after message approval and 10-row validation. After message
220
204
  validation, use Settings to help the user connect or select a LinkedIn sender.
@@ -435,23 +435,38 @@ brief`, `Revise target`, `Revise offer/proof`, and `Other / custom`.
435
435
  currentStep: "pick-provider", watchNarration: { ... } })` after approval so
436
436
  the watch link moves out of Plan while the main thread compares source paths.
437
437
 
438
- - After the brief is approved, show the next progress line:
439
- `Cool. Now I'm going to find people who are both a good fit and active enough
440
- to be worth a LinkedIn test. I'll compare source paths by expected volume,
441
- sampled ICP fit, activity/warmth signal, cleanup risk, and tradeoffs. This
442
- will end with a source decision + sample before anything goes live.`
438
+ - After the brief is approved, show the next progress line. When the user has
439
+ not given a specific source direction, use the default sequential source
440
+ funnel:
441
+ `Cool. I'm going to find people who are both a good fit and active enough to
442
+ be worth a LinkedIn test. I'll start with warm LinkedIn post engagement because
443
+ that gives the strongest message context if enough ICP-looking people are
444
+ engaging. If that does not clear a quick viability check, I'll switch to Sales
445
+ Nav with recent activity, then broader Sales Nav, and use Prospeo only as the
446
+ fallback. No leads import until you approve the source.`
447
+ - If the user's request already points to a source, do not force the default
448
+ funnel. Start with the matching lane and say why:
449
+ - specific posts, creators, topics, comments, or engagement signals ->
450
+ Signal Discovery
451
+ - title/persona/company filters or broad LinkedIn people search -> Sales Nav
452
+ - hiring signals, account/domain lists, company growth triggers, email/domain
453
+ search, or target accounts -> Prospeo
454
+ - supplied CSV/profile list -> existing/supplied list preview
455
+ - explicit compare request -> compare only the requested sources
443
456
  - In watch mode, do not leave the user sitting on only `pick-provider` while
444
- source scouts run. Move the campaign to the likely primary source lane
445
- (`signal-discovery`, `sales-nav`, or `prospeo`) before background source
446
- scouts, then run the first campaign-attached provider prompt + provider search
447
- in the parent thread with `campaignOfferId`, `confirmed: true`, and
448
- `currentStep` when the tool accepts it. Background scouts may continue after
449
- the visible campaign tab exists.
457
+ source viability is checked. Move the campaign to the first source lane that
458
+ will actually be tested (`signal-discovery`, `sales-nav`, `prospeo`, or the
459
+ user-directed lane), then run the campaign-attached provider prompt + provider
460
+ search in the parent thread with `campaignOfferId`, `confirmed: true`, and
461
+ `currentStep` when the tool accepts it. If that lane fails the quick viability
462
+ gate, update the campaign step and watchNarration before trying the next lane
463
+ so the user sees the source switch happen in the app.
450
464
  - After the lead sample/source decision is ready and approved,
451
465
  show the next progress line:
452
466
  `Lead source is set. I'll import the first 15-row review batch into the
453
- campaign table, then use that same batch to tighten the fit filter and draft the
454
- message we should test.`
467
+ campaign table, then add fit filters and draft the first message from that same
468
+ sample. You can inspect filters once they are saved, but enrichment and message
469
+ checks wait until the message draft is ready and approved.`
455
470
  - During long post-intake work, show concise progress checkpoints before the
456
471
  next expensive stage: source being checked, source switch/tradeoff if any,
457
472
  lead sample usable, filter/message drafting, and message-review rule loading.
@@ -785,42 +800,47 @@ Required behavior:
785
800
  allowed by `flow.v2.json`
786
801
  - only mutate campaign-attached source preview state in the narrow watch-mode
787
802
  ways allowed by the active flow step
788
- - run a real parallel source-angle scout when the source is not supplied and at
789
- least two viable source angles exist. Treat source scouting as independent
790
- branches, then compare the outputs in `lead-review.md`. Call
791
- `get_source_scout_registry` first so new scouts can be added without prompt
792
- rewrites. In Codex, explicitly
793
- spawn named custom subagents in the same turn when the host exposes them:
794
- `source-scout-linkedin-engagement`, `source-scout-sales-nav`, and
795
- `source-scout-prospeo-contact` for the credible lanes. Codex does not infer
796
- this from generic "compare paths" wording. If the realistic
797
- source set is LinkedIn Engagement + Sales Nav (Signals + Sales Nav), run both.
798
- If it is LinkedIn Engagement + Prospeo Contact (Signals + Prospeo), run both.
799
- If all three are credible, run all three when the host/runtime supports it.
800
- In Claude Code, launch the matching `source-scout-linkedin-engagement`,
801
- `source-scout-sales-nav`, and/or `source-scout-prospeo-contact` Task/Agent
802
- subagents in the same assistant message only when the current session lists
803
- those names, not as sequential scout turns. If they are absent, run the same
803
+ - use the default sequential source viability funnel when the user did not
804
+ specify a source. The goal is to choose a source quickly enough to keep the
805
+ watched campaign moving, not to compare every plausible lane in parallel.
806
+ Run only enough evidence for the current lane to pass or fail the quick gate,
807
+ then stop on the first viable source unless the user asked to compare.
808
+ 1. Start with LinkedIn Engagement / active LinkedIn posts (internal provider:
809
+ Signals / `signal-discovery`) because recent engagement gives the strongest
810
+ message context and expected reply-rate upside. Search relevant keyword
811
+ lanes, review finalist posts, promote the sampled posts with
812
+ `select_promising_posts` before fetching engagers when a campaign shell
813
+ exists, fetch top-post engagers, and estimate warm-fit volume.
814
+ 2. If Signals does not have enough recent, relevant, ICP-looking engagers,
815
+ switch to Sales Nav with recent activity when the target can be expressed
816
+ as title/persona/company filters. Run preview filters, inspect preview rows,
817
+ validate the filters applied, and estimate scalable-fit volume.
818
+ 3. If recent-activity Sales Nav is too small or noisy, broaden to normal Sales
819
+ Nav title + company filters and call out the weaker activity context.
820
+ 4. Use Prospeo Contact only when the campaign has a domain/account path, the
821
+ user supplied domains, the user asked for hiring/growth/account triggers,
822
+ or the LinkedIn-first paths fail. Estimate email/contact scale and call out
823
+ weaker LinkedIn activity.
824
+ - source-specific user direction overrides the default funnel. If the user
825
+ names hiring signals, account/domain lists, company growth triggers, or target
826
+ accounts, start with Prospeo. If they supply profiles or a CSV, start with the
827
+ supplied-list preview. If they name posts, comments, creators, or engagement,
828
+ start with Signal Discovery. If they name titles/personas/company filters,
829
+ start with Sales Nav. If they explicitly ask for a comparison, compare only
830
+ those requested sources.
831
+ - run source scouts in parallel only when the user explicitly requested a
832
+ comparison, the current turn is resuming from already-started parallel scouts,
833
+ or the first viable source is borderline and one cheap fallback check is
834
+ necessary for the recommendation. Call `get_source_scout_registry` first so
835
+ new scouts can be added without prompt rewrites. In Codex, explicitly spawn
836
+ named custom subagents in the same turn when the host exposes them:
837
+ `source-scout-linkedin-engagement` / LinkedIn Engagement Scout,
838
+ `source-scout-sales-nav`, and `source-scout-prospeo-contact` for the requested
839
+ or fallback lanes. Codex does not infer this from generic "compare paths"
840
+ wording. In Claude Code, launch the matching Task/Agent subagents only when
841
+ the current session lists those names. If they are absent, run the same
804
842
  provider probes with MCP tools from the parent thread and keep
805
843
  `lead-review.md` focused on source evidence, not host-agent availability.
806
- - Branch A: LinkedIn Engagement / active LinkedIn posts (internal provider:
807
- Signals / `signal-discovery`). Search relevant keyword lanes, review
808
- finalist posts, promote the sampled posts with `select_promising_posts`
809
- before fetching engagers when a campaign shell exists, fetch top-post
810
- engagers, and estimate warm-fit volume.
811
- - Branch B: Sales Nav / title + company filters. Run preview filters, inspect
812
- preview rows, and estimate scalable-fit volume.
813
- - Branch C: Prospeo Contact / domains only when the campaign has a
814
- domain/account path or the user supplied domains. Estimate email/contact
815
- scale and call out weaker LinkedIn activity.
816
- If the host cannot run these branches in parallel, run them sequentially and
817
- do not claim they ran in parallel. If only one source angle is credible, say
818
- that and run the best primary source plus one cheap fallback/quality check
819
- when available. For Signals-first campaigns, search multiple Signals keyword
820
- lanes and fetch top-post engagers in parallel when tool batching allows it.
821
- For Sales Nav-first or Prospeo/account-first campaigns, run multiple preview
822
- lanes for that provider in parallel and use Signals only as a warmth/quality
823
- check when relevant.
824
844
  - after every Sales Nav preview, validate that filters actually applied before
825
845
  using the lane in `lead-review.md`: `searchUrl` should include filters, the
826
846
  first page should match the intended roles/companies, and the result count
@@ -1006,6 +1026,25 @@ The first sentence of the visible decision must make the actual choice clear:
1006
1026
  is {source} because {reason}.` Do not make the user infer the decision from
1007
1027
  numbers alone.
1008
1028
 
1029
+ Before asking for lead-source approval, make the watched campaign show the
1030
+ recommended primary source lane. Call
1031
+ `update_campaign({ campaignId, leadSourceType: "new", leadSourceProvider,
1032
+ currentStep, watchNarration })` with `currentStep` set to the provider lane
1033
+ being recommended (`sales-nav`, `signal-discovery`, or `prospeo`). If the last
1034
+ sampled lane was Signals but the recommendation is Sales Nav, switch the
1035
+ watched provider page to Sales Nav before asking the question so the user can
1036
+ see what they are approving and why. No leads import until the user approves.
1037
+
1038
+ After the user approves a lead source, the approved provider must remain the
1039
+ active watched provider before any materialization work starts. Immediately
1040
+ call `update_campaign` again if needed with the approved `leadSourceProvider`
1041
+ and matching `currentStep` before `lookup_sales_nav_filter`,
1042
+ `get_provider_prompt`, `search_sales_nav`, `search_prospeo`, `import_leads`, or
1043
+ `confirm_lead_list`. For example, if the user approves Sales Nav while the
1044
+ browser is still showing Signal Discovery, set `leadSourceProvider: "sales-nav"`
1045
+ and `currentStep: "sales-nav"` first so the browser switches to the Sales Nav
1046
+ lane and the user can watch the approved source progress.
1047
+
1009
1048
  If you ask for lead-source approval, the question and choices must name the
1010
1049
  source decision. Prefer `Approve Sales Nav with founder/CEO filters, or use
1011
1050
  warmer Signals posts instead?` over `Approve this lead source?`. Option labels
@@ -508,6 +508,30 @@
508
508
  {
509
509
  "id": "find-leads",
510
510
  "label": "Find leads",
511
+ "sourceSelectionFunnel": {
512
+ "defaultWhenSourceUnspecified": [
513
+ "signal-discovery",
514
+ "sales-nav-recent-active",
515
+ "sales-nav-general",
516
+ "prospeo"
517
+ ],
518
+ "sourceDirectionOverrides": {
519
+ "postEngagement": "signal-discovery",
520
+ "creatorOrCommentSignals": "signal-discovery",
521
+ "titlePersonaCompanyFilters": "sales-nav",
522
+ "hiringSignals": "prospeo",
523
+ "companyGrowthTriggers": "prospeo",
524
+ "targetAccountsOrDomains": "prospeo",
525
+ "suppliedProfilesOrCsv": "supplied-list",
526
+ "explicitCompare": "compare-requested-sources"
527
+ },
528
+ "quickViabilityRule": "Run only enough of the current lane to decide whether it can supply relevant, reachable ICP-looking leads. Stop on the first viable source unless the user asked for comparison.",
529
+ "parallelAllowedOnlyWhen": [
530
+ "user explicitly requested source comparison",
531
+ "resuming already-started parallel scouts",
532
+ "first viable source is borderline and one cheap fallback check is needed"
533
+ ]
534
+ },
511
535
  "onEnter": [
512
536
  {
513
537
  "action": "advance_watch_to_source_selection",
@@ -521,8 +545,8 @@
521
545
  "currentStep": "pick-provider",
522
546
  "watchNarration.stage": "find-leads"
523
547
  },
524
- "when": "before_source_scouts_or_provider_search",
525
- "chatRenderRule": "Move the campaign watch view to Find Leads before the main thread starts comparing source paths. The watchNarration headline/body must name the likely provider or lane being tested and why it fits this campaign. Do not mention MCP or local artifacts."
548
+ "when": "before_sequential_source_funnel",
549
+ "chatRenderRule": "Move the campaign watch view to Find Leads before the main thread starts source viability work. If the user did not specify a source, explain the default order: start with warm LinkedIn post engagement because it gives stronger message context and expected reply-rate upside when enough ICP-looking engagers exist; if it is not viable, switch to Sales Nav with recent activity, then broader Sales Nav, and use Prospeo only as the fallback. If the user did specify hiring signals, domains/accounts, supplied lists, posts/comments, or titles/personas, explain that the matching source overrides the default funnel. State that no leads import until a source is approved. The watchNarration headline/body must name the lane being tested, why this lane now, the quick viability gate, and the safety boundary. Do not mention MCP or local artifacts."
526
550
  },
527
551
  {
528
552
  "action": "advance_watch_to_initial_source_lane",
@@ -540,8 +564,8 @@
540
564
  "existingList": "saved-lists",
541
565
  "uploadedDomains": "prospeo"
542
566
  },
543
- "when": "before_background_source_scouts",
544
- "rule": "Choose the likely primary visible source lane from source intake, brief preference, or the best first lane the main thread will actually search. Send watchNarration with stage find-leads that says what search was tried or is being tried next, what sample is being checked, and why it helps this campaign. For Signal Discovery sampling, promote/select the posts with select_promising_posts before fetch_post_engagers so the watched table shows the exact posts being sampled; the guide copy should say Codex is pulling sample engagers from these posts to confirm the ICP is actually engaging and the source is viable. Do this before waiting on background scouts so watch mode never sits on only Pick Provider while source work happens elsewhere."
567
+ "when": "before_first_source_attempt",
568
+ "rule": "Choose the first visible source lane from explicit source direction when present, otherwise default to Signal Discovery. Send watchNarration with stage find-leads that says why this lane is being tried now, what quick sample or filter gate will pass/fail it, and why that helps this campaign. For Signal Discovery sampling, promote/select the posts with select_promising_posts before fetch_post_engagers so the watched table shows the exact posts being sampled; the guide copy should say Codex is pulling sample engagers from these posts to confirm the ICP is actually engaging and the source is viable. If the lane fails, update currentStep and watchNarration before moving to Sales Nav recent activity, normal Sales Nav, or Prospeo."
545
569
  },
546
570
  {
547
571
  "action": "run_first_campaign_attached_source_search",
@@ -549,8 +573,8 @@
549
573
  "campaignOfferId",
550
574
  "currentStep"
551
575
  ],
552
- "before": "waiting_on_background_source_scouts",
553
- "rule": "Before relying on background source scouts, the parent thread must run the first provider prompt + provider search for the chosen visible lane with campaignOfferId and currentStep (signal-discovery, sales-nav, or prospeo) so the campaign UI creates the corresponding live search/tab. Background scouts may continue after that, but the user must see at least one relevant campaign-attached search begin in the watched page."
576
+ "before": "evaluating_source_viability_gate",
577
+ "rule": "The parent thread must run the campaign-attached provider prompt + provider search for the current visible lane with campaignOfferId and currentStep (signal-discovery, sales-nav, prospeo, or the user-directed lane) so the campaign UI creates the corresponding live search/tab. Do not wait on background scouts before the user sees the active lane. Run only enough evidence to pass/fail this lane, then either recommend it or update the visible lane before trying the next fallback."
554
578
  },
555
579
  {
556
580
  "action": "render_find_leads_progress",
@@ -558,6 +582,9 @@
558
582
  "good fit and active enough to be worth a LinkedIn test",
559
583
  "campaign source step",
560
584
  "primary source",
585
+ "source hypothesis",
586
+ "why this source now",
587
+ "quick viability gate",
561
588
  "expected volume",
562
589
  "sampled ICP fit",
563
590
  "activity/warmth signal",
@@ -587,7 +614,7 @@
587
614
  "action": "run_subskill",
588
615
  "target": "find-leads",
589
616
  "mode": "campaign-attached-required",
590
- "sourceScoutRule": "Shell-first flow requires the CampaignOffer campaignId from durable state. Pass campaignId as campaignOfferId into every provider prompt/search that can persist source state (`get_provider_prompt({ provider, campaignOfferId, confirmed: true })`, `search_signals`, `search_sales_nav`, `search_prospeo`) and include currentStep for tools that accept it so the user can watch the selected source inside the campaign. In watch mode, run the first campaign-attached provider search in the parent thread before waiting on background scouts; subagents can explore runner-up lanes after the visible campaign tab exists. The later import_leads call must use the same campaignOfferId. When several source lanes are credible, scout them independently, then write one primary source recommendation and any runner-up tradeoffs. Do not import, confirm, enrich, queue, or start leads during source discovery."
617
+ "sourceScoutRule": "Shell-first flow requires the CampaignOffer campaignId from durable state. Pass campaignId as campaignOfferId into every provider prompt/search that can persist source state (`get_provider_prompt({ provider, campaignOfferId, confirmed: true })`, `search_signals`, `search_sales_nav`, `search_prospeo`) and include currentStep for tools that accept it so the user can watch the selected source inside the campaign. Use the default sequential source viability funnel when the user did not specify a source: Signal Discovery first, then Sales Nav with recent activity, then general Sales Nav, then Prospeo only as fallback. Stop on the first viable source unless the user explicitly asked to compare. If the user names hiring signals, domains/accounts, supplied lists, posts/comments, or title/persona filters, start with the matching source instead. Parallel source scouts only when the user requested comparison, an existing parallel run is being resumed, or the first viable source is borderline and one cheap fallback check is needed. The later import_leads call must use the same campaignOfferId. Do not import, confirm, enrich, queue, or start leads during source discovery."
591
618
  },
592
619
  {
593
620
  "action": "optional_debug_artifacts",
@@ -745,7 +772,7 @@
745
772
  "artifactLinkTiming": "before_next_step_or_revision_question",
746
773
  "doNotCompressToSummaryOnly": false,
747
774
  "doNotRenderArtifactLinksOnly": true,
748
- "sourceRecommendationReadyWatchRule": "When the source recommendation decision card is ready in chat with counts and sample quality, update watchNarration to a find-leads chat-handoff frame. Use a headline like `Review the source in Codex`, body copy that says the browser is showing the evaluated source/results, and nextAction like `Approve in Codex`. Do not keep future-tense copy like `I'll show a source recommendation` after the decision is visible. Include a safety note that no leads import until the user approves the source.",
775
+ "sourceRecommendationReadyWatchRule": "When the source recommendation decision card is ready in chat with counts and sample quality, and before asking for source approval, call update_campaign with leadSourceType `new`, leadSourceProvider set to the recommended primary provider, currentStep set to that provider lane (`sales-nav`, `signal-discovery`, or `prospeo`), and find-leads watchNarration. If the recommendation changed from the lane last sampled, switch the watched provider page to the recommended lane first so the user can inspect what they are approving. Use a headline like `Review the source in Codex`, body copy that says the browser is showing the evaluated source/results, and nextAction like `Approve in Codex`. Do not keep future-tense copy like `I'll show a source recommendation` after the decision is visible. Include a safety note that no leads import until the user approves the source.",
749
776
  "chatRenderRule": "Show a slim rendered-Markdown decision summary only, never a fenced code block. The first sentence must make the decision explicit: 'I recommend {primary source} using {exact filter/source recipe}. The runner-up is {source} because {reason}.' Use indexed sections and short bullets: recommendation, Primary source and filters, Runner-up sources, why it won, Quick numbers with one provider/source angle per bullet, raw volume, sampled fit count as n/N only (no percentages), estimated good-fit range after cleanup, activity/warmth basis, confidence note, 3-5 representative sample leads, and one tradeoff. Do not forecast connection acceptance rates, reply rates, meetings, pipeline, revenue, or ROI unless the user supplied verified benchmark data for this exact workspace/sender. If Signals was searched or considered, include two compact inline Markdown tables before the recommendation is treated as final: Signal keyword lanes with keyword lane, timeframe, posts found, and finalist posts reviewed; and LinkedIn posts sampled with post URL/title, author/topic, age, engagers, sampled engagers, good fits as n/N only, estimated usable prospects per post, and use/discard decision. Default to selecting a few promising Signals posts for the first sample instead of trying to prove full Signals scale up front; if the sample is good but volume is low, say how many more posts to add/scrape next. Do not skip or discard Signals based only on raw post count or vibes; show the post-level math first, or explicitly say no engagers could be fetched and lower confidence. Keep discarded paths, full sample rows, and lead-sample.json details in lead-review.md. Do not show plain filesystem paths unless links cannot be created."
750
777
  },
751
778
  {
@@ -796,6 +823,7 @@
796
823
  "watchNarration: find-leads source recommendation ready, or review-batch import starting when source approval already happened",
797
824
  "selectedLeadListId as source list id only for existing-list or supplied-list preview"
798
825
  ],
826
+ "sourceApprovalWatchRule": "Immediately after the user approves a source, and before lookup_sales_nav_filter, get_provider_prompt, search_sales_nav, search_prospeo, import_leads, or confirm_lead_list, persist the approved source as the active provider on the CampaignOffer. For Sales Nav approval, call update_campaign with leadSourceType `new`, leadSourceProvider `sales-nav`, currentStep `sales-nav`, and current-tense watchNarration so the browser switches off the previous Signal Discovery lane and the user can continue watching the approved provider setup. Apply the same rule for signal-discovery and prospeo approvals.",
799
827
  "fallback": "Stop if campaignId is missing; the source must be attached to the existing CampaignOffer before import.",
800
828
  "readsCampaignStateFirst": true
801
829
  }
@@ -875,7 +903,7 @@
875
903
  },
876
904
  {
877
905
  "action": "watch_mode_orient",
878
- "watchNarrationRule": "Before import_leads or confirm_lead_list starts, align the guide with chat by setting review-batch watchNarration to current-tense import copy. Use a headline like `Importing the review batch`; explain that the browser may still show the approved source leads while Codex imports only the bounded 15-row review batch; include a no-launch safety note."
906
+ "watchNarrationRule": "Before import_leads or confirm_lead_list starts, align the guide with chat by setting review-batch watchNarration to current-tense import copy. Also persist the approved source provider/currentStep first: Sales Nav approval must set leadSourceProvider `sales-nav` and currentStep `sales-nav`, Signals approval must set `signal-discovery`, and Prospeo approval must set `prospeo`. Use a headline like `Importing the review batch`; explain that the browser is on the approved source lane while Codex imports only the bounded 15-row review batch; include a no-launch safety note."
879
907
  },
880
908
  {
881
909
  "tool": "import_leads",
@@ -943,8 +971,10 @@
943
971
  ],
944
972
  "requiredValues": {
945
973
  "currentStep": "filter-choice",
946
- "watchNarration.stage": "fit-message"
947
- }
974
+ "watchNarration.stage": "fit-message",
975
+ "watchNarration.headline": "Added to Campaign"
976
+ },
977
+ "watchNarrationRule": "After the bounded review batch is present, update the watched guide to `Added to Campaign`. Say Codex is adding fit filters so every send stays qualified while drafting the first message in the background. This persists add-filters intent by currentStep/watchNarration only; do not set enableICPFilters=true until save_rubrics succeeds with active criteria. Nothing enriches, validates, or sends until the first message is ready and approved."
948
978
  }
949
979
  ],
950
980
  "allowedTools": [
@@ -74,6 +74,45 @@ Signal Discovery:
74
74
  }
75
75
  ```
76
76
 
77
+ Default source funnel:
78
+
79
+ ```json
80
+ {
81
+ "stage": "find-leads",
82
+ "headline": "Testing warm LinkedIn activity",
83
+ "visibleState": "Codex is starting with recent post engagement because it gives the strongest message context if enough ICP-looking people are active there.",
84
+ "agentIntent": "If this lane does not clear the quick sample gate, it will switch to Sales Nav with recent activity, then broader Sales Nav, and use Prospeo only as the fallback.",
85
+ "nextAction": "Review source",
86
+ "safety": "No leads import until you approve the source."
87
+ }
88
+ ```
89
+
90
+ Source direction override:
91
+
92
+ ```json
93
+ {
94
+ "stage": "find-leads",
95
+ "headline": "Testing the requested source",
96
+ "visibleState": "The campaign asked for hiring and account signals, so Codex is starting with Prospeo instead of the default LinkedIn engagement path.",
97
+ "agentIntent": "It is checking whether this source has enough reachable ICP-looking people before importing a review batch.",
98
+ "nextAction": "Review source",
99
+ "safety": "No leads import until you approve the source."
100
+ }
101
+ ```
102
+
103
+ Source fallback:
104
+
105
+ ```json
106
+ {
107
+ "stage": "find-leads",
108
+ "headline": "Switching source lanes",
109
+ "visibleState": "The Signal Discovery sample did not show enough ICP-looking engagers for a confident first batch.",
110
+ "agentIntent": "Codex is trying Sales Nav with recent activity so the source can still preserve some buyer activity context.",
111
+ "nextAction": "Review source",
112
+ "safety": "No leads import until you approve the source."
113
+ }
114
+ ```
115
+
77
116
  Search iteration:
78
117
 
79
118
  ```json
@@ -134,6 +173,27 @@ current-tense import copy. Do not leave the guide in source-approved or
134
173
  future-tense copy such as `I'll show the review-batch outcome`; that makes the
135
174
  browser guide describe a different moment than chat.
136
175
 
176
+ After review batch import:
177
+
178
+ ```json
179
+ {
180
+ "stage": "fit-message",
181
+ "headline": "Added to Campaign",
182
+ "visibleState": "The first review batch is in the campaign.",
183
+ "agentIntent": "Codex is adding fit filters to keep every send qualified while drafting the first message in the background.",
184
+ "nextAction": "Review fit rules and message",
185
+ "safety": "Nothing enriches, validates, or sends until the message is ready and approved.",
186
+ "workerStatuses": {
187
+ "leadFitBuilder": "running",
188
+ "messageDraftBuilder": "running"
189
+ }
190
+ }
191
+ ```
192
+
193
+ Use this after the selected review rows are present and before filters are
194
+ saved. This is add-filters intent, not active filtering. `enableICPFilters`
195
+ only becomes true after active filter criteria are saved.
196
+
137
197
  Fit + message:
138
198
 
139
199
  ```json
@@ -0,0 +1,9 @@
1
+ {
2
+ "parallelMode": "wide",
3
+ "agentCount": 6,
4
+ "maxToolCallsPerAgent": 2,
5
+ "senderMaxAgents": 2,
6
+ "senderMaxToolCallsPerAgent": 3,
7
+ "progressMode": true,
8
+ "debugMode": true
9
+ }