@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 +0 -0
- package/dist/index.js +0 -0
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +21 -37
- package/skills/create-campaign-v2/SKILL.md +86 -47
- package/skills/create-campaign-v2/core/flow.v2.json +41 -11
- package/skills/create-campaign-v2/references/watch-guide-narration.md +60 -0
- package/skills/research/config.json +9 -0
package/dist/index-dev.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -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
|
|
171
|
-
A valid handoff link must be a
|
|
172
|
-
`/campaign-builder/{campaignId}?mode=claude|codex
|
|
173
|
-
|
|
174
|
-
`get_campaign.watchUrl` are all
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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:
|
|
182
|
+
Watch link: {watchUrl}
|
|
198
183
|
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
`create_campaign({ campaignId })` or `get_campaign
|
|
208
|
-
link. Do not claim the browser was opened, inspected, or
|
|
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
|
|
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
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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
|
|
445
|
-
(`signal-discovery`, `sales-nav`,
|
|
446
|
-
|
|
447
|
-
in the parent thread with `campaignOfferId`, `confirmed: true`, and
|
|
448
|
-
`currentStep` when the tool accepts it.
|
|
449
|
-
the
|
|
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
|
|
454
|
-
|
|
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
|
-
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
If
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
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": "
|
|
525
|
-
"chatRenderRule": "Move the campaign watch view to Find Leads before the main thread starts
|
|
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": "
|
|
544
|
-
"rule": "Choose the
|
|
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": "
|
|
553
|
-
"rule": "
|
|
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.
|
|
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,
|
|
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
|
|
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
|