@sellable/mcp 0.1.140 → 0.1.142
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/README.md +5 -4
- package/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/server.js +29 -59
- package/dist/tools/auth.js +5 -5
- package/dist/tools/leads.d.ts +47 -5
- package/dist/tools/leads.js +93 -16
- package/dist/tools/navigation.js +6 -1
- package/dist/tools/registry.d.ts +4186 -0
- package/dist/tools/registry.js +59 -0
- package/dist/tools/rubrics.js +15 -14
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +34 -23
- package/skills/create-campaign-v2/SKILL.md +25 -15
- package/skills/create-campaign-v2/SOUL.md +19 -19
- package/skills/create-campaign-v2/core/flow.v2.json +65 -11
- package/skills/create-campaign-v2/references/watch-guide-narration.md +3 -1
- package/skills/find-leads/SKILL.md +3 -3
- package/skills/interview/SKILL.md +53 -0
- package/skills/interview/references/voice-capture-method.md +12 -1
- package/skills/research/config.json +0 -9
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { authToolDefinitions } from "./auth.js";
|
|
2
|
+
import { blueprintCommitToolDefinitions } from "./blueprint-commit.js";
|
|
3
|
+
import { bootstrapToolDefinitions } from "./bootstrap.js";
|
|
4
|
+
import { campaignToolDefinitions } from "./campaigns.js";
|
|
5
|
+
import { cellToolDefinitions } from "./cells.js";
|
|
6
|
+
import { startCliLoginToolDef, waitForCliLoginToolDef } from "./cli-login.js";
|
|
7
|
+
import { contextToolDefinitions } from "./context.js";
|
|
8
|
+
import { directCampaignToolDefinitions } from "./direct-campaigns.js";
|
|
9
|
+
import { engageBootstrapToolDefinitions } from "./engage-bootstrap.js";
|
|
10
|
+
import { engageDiscoveryToolDefinitions } from "./engage-discovery.js";
|
|
11
|
+
import { engageMemoryToolDefinitions } from "./engage-memory.js";
|
|
12
|
+
import { engageStateToolDefinitions } from "./engage-state.js";
|
|
13
|
+
import { enrichmentToolDefinitions } from "./enrichment.js";
|
|
14
|
+
import { frameworkToolDefinitions } from "./framework.js";
|
|
15
|
+
import { leadToolDefinitions } from "./leads.js";
|
|
16
|
+
import { linkedinToolDefinitions } from "./linkedin.js";
|
|
17
|
+
import { navigationToolDefinitions } from "./navigation.js";
|
|
18
|
+
import { onDemandToolDefinitions } from "./one-off.js";
|
|
19
|
+
import { processingToolDefinitions } from "./processing.js";
|
|
20
|
+
import { promptToolDefinitions } from "./prompts.js";
|
|
21
|
+
import { readinessToolDefinitions } from "./readiness.js";
|
|
22
|
+
import { rowToolDefinitions } from "./rows.js";
|
|
23
|
+
import { rubricToolDefinitions } from "./rubrics.js";
|
|
24
|
+
import { senderToolDefinitions } from "./senders.js";
|
|
25
|
+
import { sequencerToolDefinitions } from "./sequencer.js";
|
|
26
|
+
import { tableToolDefinitions } from "./tables.js";
|
|
27
|
+
import { verifyRowToolDefinitions } from "./verify-row.js";
|
|
28
|
+
import { workspaceToolDefinitions } from "./workspaces.js";
|
|
29
|
+
export const allTools = [
|
|
30
|
+
...campaignToolDefinitions,
|
|
31
|
+
...authToolDefinitions,
|
|
32
|
+
startCliLoginToolDef,
|
|
33
|
+
waitForCliLoginToolDef,
|
|
34
|
+
...bootstrapToolDefinitions,
|
|
35
|
+
...engageBootstrapToolDefinitions,
|
|
36
|
+
...engageDiscoveryToolDefinitions,
|
|
37
|
+
...workspaceToolDefinitions,
|
|
38
|
+
...frameworkToolDefinitions,
|
|
39
|
+
...contextToolDefinitions,
|
|
40
|
+
...navigationToolDefinitions,
|
|
41
|
+
...leadToolDefinitions,
|
|
42
|
+
...enrichmentToolDefinitions,
|
|
43
|
+
...processingToolDefinitions,
|
|
44
|
+
...rubricToolDefinitions,
|
|
45
|
+
...readinessToolDefinitions,
|
|
46
|
+
...rowToolDefinitions,
|
|
47
|
+
...cellToolDefinitions,
|
|
48
|
+
...promptToolDefinitions,
|
|
49
|
+
...linkedinToolDefinitions,
|
|
50
|
+
...onDemandToolDefinitions,
|
|
51
|
+
...directCampaignToolDefinitions,
|
|
52
|
+
...senderToolDefinitions,
|
|
53
|
+
...engageStateToolDefinitions,
|
|
54
|
+
...engageMemoryToolDefinitions,
|
|
55
|
+
...sequencerToolDefinitions,
|
|
56
|
+
...tableToolDefinitions,
|
|
57
|
+
...blueprintCommitToolDefinitions,
|
|
58
|
+
...verifyRowToolDefinitions,
|
|
59
|
+
];
|
package/dist/tools/rubrics.js
CHANGED
|
@@ -89,16 +89,16 @@ async function fetchCampaignOffer(campaignOfferId) {
|
|
|
89
89
|
leadScoringRubrics: v3.rubrics,
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
|
-
const
|
|
92
|
+
const filterLeadsReadyWatchNarration = {
|
|
93
93
|
stage: "fit-message",
|
|
94
|
-
headline: "
|
|
95
|
-
visibleState: "Filters are enabled and the browser is showing Filter
|
|
96
|
-
agentIntent: "Codex is
|
|
97
|
-
nextAction: "Review
|
|
94
|
+
headline: "Filter Leads is ready",
|
|
95
|
+
visibleState: "Filters are enabled, rubrics are saved, and the browser is showing Filter Leads.",
|
|
96
|
+
agentIntent: "Codex is waiting for the approved message template before running enrichment, filtering, or message cells.",
|
|
97
|
+
nextAction: "Review or approve the message template before filtering",
|
|
98
98
|
progressLabel: "Fit + message",
|
|
99
|
-
safety: "
|
|
99
|
+
safety: "Saved rules do not start enrichment, filtering, Generate Message cells, sequence setup, or sending.",
|
|
100
100
|
};
|
|
101
|
-
function
|
|
101
|
+
function shouldMoveToFilterLeads(currentStep) {
|
|
102
102
|
if (!currentStep)
|
|
103
103
|
return true;
|
|
104
104
|
return [
|
|
@@ -106,15 +106,16 @@ function shouldMoveToFilterRules(currentStep) {
|
|
|
106
106
|
"filter-choice",
|
|
107
107
|
"create-icp-rubric",
|
|
108
108
|
"filter-rules",
|
|
109
|
+
"apply-icp-rubric",
|
|
109
110
|
].includes(currentStep);
|
|
110
111
|
}
|
|
111
112
|
function buildEnableIcpFiltersPayload(currentStep) {
|
|
112
113
|
const payload = {
|
|
113
114
|
enableICPFilters: true,
|
|
114
115
|
};
|
|
115
|
-
if (
|
|
116
|
-
payload.currentStep = "
|
|
117
|
-
payload.watchNarration =
|
|
116
|
+
if (shouldMoveToFilterLeads(currentStep)) {
|
|
117
|
+
payload.currentStep = "apply-icp-rubric";
|
|
118
|
+
payload.watchNarration = filterLeadsReadyWatchNarration;
|
|
118
119
|
}
|
|
119
120
|
return payload;
|
|
120
121
|
}
|
|
@@ -234,7 +235,7 @@ export const rubricToolDefinitions = [
|
|
|
234
235
|
},
|
|
235
236
|
{
|
|
236
237
|
name: "save_rubrics",
|
|
237
|
-
description: "Persist rubric criteria to the campaign. Pass leadScoringRubrics directly to save without drafting. Saving active rubrics enables ICP filtering and
|
|
238
|
+
description: "Persist rubric criteria to the campaign. Pass leadScoringRubrics directly to save without drafting. Saving active rubrics enables ICP filtering and moves the watched client to Filter Leads; it does not run filtering by itself.",
|
|
238
239
|
inputSchema: {
|
|
239
240
|
type: "object",
|
|
240
241
|
properties: {
|
|
@@ -570,7 +571,7 @@ export async function saveRubrics(input) {
|
|
|
570
571
|
const payload = buildEnableIcpFiltersPayload(campaign.currentStep);
|
|
571
572
|
await api.put(`/api/v2/campaign-offers/${input.campaignOfferId}`, payload);
|
|
572
573
|
enableICPFiltersSet = true;
|
|
573
|
-
currentStepSet = payload.currentStep === "
|
|
574
|
+
currentStepSet = payload.currentStep === "apply-icp-rubric";
|
|
574
575
|
}
|
|
575
576
|
catch (error) {
|
|
576
577
|
// Non-fatal: the rubric save already succeeded. Retry the minimum
|
|
@@ -590,7 +591,7 @@ export async function saveRubrics(input) {
|
|
|
590
591
|
return {
|
|
591
592
|
success: true,
|
|
592
593
|
message: currentStepSet
|
|
593
|
-
? `Saved ${normalizedDraft.length} rubric criteria, ICP filtering is ON, and the campaign is on Filter
|
|
594
|
+
? `Saved ${normalizedDraft.length} rubric criteria, ICP filtering is ON, and the campaign is on Filter Leads.`
|
|
594
595
|
: enableICPFiltersSet || campaign.enableICPFilters === true
|
|
595
596
|
? `Saved ${normalizedDraft.length} rubric criteria and ICP filtering is ON.`
|
|
596
597
|
: `Saved ${normalizedDraft.length} rubric criteria to the campaign. WARNING: could not auto-enable ICP filtering — call update_campaign({ campaignId, enableICPFilters: true }) to activate rubric-based filtering.`,
|
|
@@ -598,7 +599,7 @@ export async function saveRubrics(input) {
|
|
|
598
599
|
deletedCount: deletedRubricIds.length,
|
|
599
600
|
enableICPFiltersSet,
|
|
600
601
|
currentStep: currentStepSet
|
|
601
|
-
? "
|
|
602
|
+
? "apply-icp-rubric"
|
|
602
603
|
: (campaign.currentStep ?? null),
|
|
603
604
|
currentStepSet,
|
|
604
605
|
rubrics: result?.rubrics ?? normalizedDraft,
|
package/package.json
CHANGED
|
@@ -16,7 +16,6 @@ allowed-tools:
|
|
|
16
16
|
- mcp__sellable__get_active_workspace
|
|
17
17
|
- mcp__sellable__list_senders
|
|
18
18
|
- mcp__sellable__get_sender
|
|
19
|
-
- mcp__sellable__enrich_sender
|
|
20
19
|
- mcp__sellable__complete_sender_research
|
|
21
20
|
- mcp__sellable__fetch_linkedin_profile
|
|
22
21
|
- mcp__sellable__fetch_linkedin_posts
|
|
@@ -54,7 +53,6 @@ allowed-tools:
|
|
|
54
53
|
- mcp__sellable__load_csv_linkedin_leads
|
|
55
54
|
- mcp__sellable__load_csv_domains
|
|
56
55
|
- mcp__sellable__queue_cells
|
|
57
|
-
- mcp__sellable__generate_messages
|
|
58
56
|
- mcp__sellable__get_campaign_messages_preview
|
|
59
57
|
- mcp__sellable__attach_sequence
|
|
60
58
|
- mcp__sellable__attach_recommended_sequence
|
|
@@ -63,7 +61,10 @@ allowed-tools:
|
|
|
63
61
|
|
|
64
62
|
# Sellable Create Campaign
|
|
65
63
|
|
|
66
|
-
Use this as the customer-facing
|
|
64
|
+
Use this as the customer-facing public wrapper for Sellable campaign creation.
|
|
65
|
+
It bootstraps auth and host capabilities, then loads the internal
|
|
66
|
+
`create-campaign-v2` workflow prompt and `core/flow.v2.json` through MCP. Keep
|
|
67
|
+
this wrapper thin; v2 is the operational source of truth.
|
|
67
68
|
|
|
68
69
|
CampaignOffer state and the watch link are the customer-facing source of truth.
|
|
69
70
|
Disk artifacts are optional debug/UAT diagnostics; normal customer runs should
|
|
@@ -118,7 +119,8 @@ signals, cleanup risk, and confidence basis. If a user asks for a forecast,
|
|
|
118
119
|
label it explicitly as not estimated from this run.
|
|
119
120
|
|
|
120
121
|
Before any provider prompt, search, source scout, or signal-discovery call,
|
|
121
|
-
show a short source-plan gate and ask for approval.
|
|
122
|
+
show a short source-plan gate and ask for approval. This first approval
|
|
123
|
+
authorizes scouting/search only. The gate should say:
|
|
122
124
|
|
|
123
125
|
- given this campaign, the viable source options
|
|
124
126
|
- the recommended first lane
|
|
@@ -127,14 +129,19 @@ show a short source-plan gate and ask for approval. The gate should say:
|
|
|
127
129
|
- the fallback lane if relevant posts or ICP engagement look thin
|
|
128
130
|
- that approval authorizes scouting/search only, not lead import or sending
|
|
129
131
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
`
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
Do not surface blanket source heuristics as product copy. Make the
|
|
133
|
+
recommendation specific to the campaign. If Signal Discovery is recommended,
|
|
134
|
+
name the exact post themes you will search. If relevant public conversations
|
|
135
|
+
look unlikely, recommend the specific Sales Nav or Prospeo lane instead and say
|
|
136
|
+
why. Do not call `search_signals`, `search_sales_nav`, `search_prospeo`,
|
|
137
|
+
`fetch_post_engagers`, or provider-scoped subagents until the user approves this
|
|
138
|
+
source plan or explicitly chooses a different source.
|
|
139
|
+
|
|
140
|
+
After scouting, ask for a second approval on the concrete source action. For
|
|
141
|
+
Signal Discovery, name how many selected posts will be scraped, the target
|
|
142
|
+
engager/source-candidate volume, and the bounded review-batch size. For Sales
|
|
143
|
+
Nav or Prospeo, name the specific approved import lane. Do not call
|
|
144
|
+
`import_leads` or `confirm_lead_list` until this second approval is granted.
|
|
138
145
|
|
|
139
146
|
When the user has not supplied a source and multiple source angles are viable,
|
|
140
147
|
scout those angles as independent branches when the host can actually do it:
|
|
@@ -331,7 +338,7 @@ the brief. This is only the client-prospect/bootstrap identity for
|
|
|
331
338
|
Do not call `mcp__sellable__list_senders`, `mcp__sellable__get_sender`, or
|
|
332
339
|
surface connected/missing sender state during setup, brief, source, filter, or
|
|
333
340
|
message review. Sender availability belongs only to the Settings/final launch
|
|
334
|
-
handoff after message approval and the
|
|
341
|
+
handoff after message approval and the review-batch validation sample.
|
|
335
342
|
|
|
336
343
|
If the invocation or user answer includes an existing `clientProspectId`, keep
|
|
337
344
|
it as the preferred `create_campaign` identity input. If it includes a LinkedIn
|
|
@@ -537,9 +544,9 @@ updates.
|
|
|
537
544
|
```text
|
|
538
545
|
You're in — {activeWorkspaceName} workspace, ready to roll.
|
|
539
546
|
|
|
540
|
-
Now — paste the LinkedIn profile
|
|
547
|
+
Now — paste the LinkedIn profile or company website for the client/company this campaign is for. I’ll use that to resolve the campaign identity before we pick the target, offer, proof, and lead source.
|
|
541
548
|
|
|
542
|
-
e.g. https://www.linkedin.com/in/
|
|
549
|
+
e.g. https://example.com or https://www.linkedin.com/in/client-handle
|
|
543
550
|
```
|
|
544
551
|
|
|
545
552
|
- If `isReturningUser === false`, prepend ONE line confirming the new
|
|
@@ -548,16 +555,18 @@ updates.
|
|
|
548
555
|
```text
|
|
549
556
|
You're set up — your {activeWorkspaceName} workspace is ready.
|
|
550
557
|
|
|
551
|
-
Now — paste the LinkedIn profile
|
|
558
|
+
Now — paste the LinkedIn profile or company website for the client/company this campaign is for. I’ll use that to resolve the campaign identity before we pick the target, offer, proof, and lead source.
|
|
552
559
|
|
|
553
|
-
e.g. https://www.linkedin.com/in/
|
|
560
|
+
e.g. https://example.com or https://www.linkedin.com/in/client-handle
|
|
554
561
|
```
|
|
555
562
|
|
|
556
563
|
No other lines. No "all set", no "signed in", no other acknowledgement.
|
|
557
564
|
|
|
558
|
-
After the user pastes the URL, proceed with the
|
|
559
|
-
|
|
560
|
-
|
|
565
|
+
After the user pastes the URL, proceed with the identity-first campaign
|
|
566
|
+
setup in the v2 subskill prompt. Resolve a LinkedIn profile with
|
|
567
|
+
`fetch_linkedin_profile`, a company website/domain with `fetch_company`
|
|
568
|
+
when possible, and mark the client/company research gate with
|
|
569
|
+
`complete_sender_research` when that protocol is required.
|
|
561
570
|
|
|
562
571
|
3. If auth is not OK with `error.type === "workspace"` (token valid, no active
|
|
563
572
|
workspace), stop and show the returned guidance — that's not a fresh-user
|
|
@@ -599,8 +608,9 @@ updates.
|
|
|
599
608
|
is synced into the campaign brief. When filters are approved, immediately
|
|
600
609
|
call `mcp__sellable__update_campaign({ campaignId, enableICPFilters: true, currentStep: "create-icp-rubric", watchNarration })`
|
|
601
610
|
so the watched app moves to Filter Rules while rubrics are drafted/saved.
|
|
602
|
-
After rubrics save,
|
|
603
|
-
|
|
611
|
+
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
|
|
604
614
|
`enrichCellId` cells to kick off enrichment/filtering.
|
|
605
615
|
Product Generate Message cells must not run from the background template
|
|
606
616
|
path before that template/token approval.
|
|
@@ -611,7 +621,8 @@ updates.
|
|
|
611
621
|
visible work so the user can watch progress in the app: `create-offer` for
|
|
612
622
|
the brief, `pick-provider` or the selected provider step while sourcing,
|
|
613
623
|
`filter-choice` after the 15-row review batch, `create-icp-rubric` as soon
|
|
614
|
-
as filters are approved, `
|
|
624
|
+
as filters are approved, `apply-icp-rubric` after rubrics save, `messages`
|
|
625
|
+
for the Use Template / AI Generated mode
|
|
615
626
|
choice, `auto-execute-messaging` for approved
|
|
616
627
|
message work or the product's AI-generated path, `awaiting-user-greenlight`
|
|
617
628
|
for the final handoff, `settings` for sender selection, `sequence` after
|
|
@@ -123,8 +123,8 @@ Default source order when the user has not supplied a source:
|
|
|
123
123
|
4. Prospeo account/contact expansion
|
|
124
124
|
|
|
125
125
|
Before any provider prompt, search, source scout, or signal-discovery call,
|
|
126
|
-
show a short source-plan gate and ask for approval.
|
|
127
|
-
language:
|
|
126
|
+
show a short source-plan gate and ask for approval. This first approval
|
|
127
|
+
authorizes source scouting/search only. The gate must say, in plain language:
|
|
128
128
|
|
|
129
129
|
- given this campaign, the viable source options
|
|
130
130
|
- the recommended first lane
|
|
@@ -133,14 +133,13 @@ language:
|
|
|
133
133
|
- the fallback lane if relevant posts or ICP engagement look thin
|
|
134
134
|
- that approval authorizes scouting/search only, not lead import or sending
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
public
|
|
140
|
-
|
|
141
|
-
`
|
|
142
|
-
|
|
143
|
-
different source.
|
|
136
|
+
Do not surface blanket source heuristics as product copy. Make the recommendation
|
|
137
|
+
specific to the campaign. If Signal Discovery is recommended, name the exact
|
|
138
|
+
post themes you will search. If the campaign looks unlikely to have relevant
|
|
139
|
+
public conversations, recommend the specific Sales Nav or Prospeo lane instead
|
|
140
|
+
and say why. Do not call `search_signals`, `search_sales_nav`, `search_prospeo`,
|
|
141
|
+
`fetch_post_engagers`, or provider-scoped subagents until the user approves this
|
|
142
|
+
source plan or explicitly chooses a different source.
|
|
144
143
|
|
|
145
144
|
Call `get_source_scout_registry` before source scouting. Source scouting is
|
|
146
145
|
sequential by default. Run `source-scout-linkedin-engagement`,
|
|
@@ -148,10 +147,19 @@ sequential by default. Run `source-scout-linkedin-engagement`,
|
|
|
148
147
|
when the user explicitly requested source comparison, a prior lane failed, or
|
|
149
148
|
the first viable lane is borderline and a cheap fallback check is needed.
|
|
150
149
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
cleanup risk,
|
|
150
|
+
After scouting, show a second approval gate for the concrete source action. For
|
|
151
|
+
Signal Discovery, this gate must say how many selected posts will be scraped,
|
|
152
|
+
the target engager/source-candidate volume, the bounded campaign review-batch
|
|
153
|
+
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.
|
|
158
|
+
|
|
159
|
+
A source recommendation must show concrete evidence: source lane, filters or
|
|
160
|
+
recipe, raw volume, sample size, sampled fits as n/N plus percentage/range,
|
|
161
|
+
estimated usable prospects, cleanup risk, runner-up, and what approval
|
|
162
|
+
authorizes.
|
|
155
163
|
|
|
156
164
|
Supplied profile CSVs, company/domain CSVs, pasted domains, and existing
|
|
157
165
|
Sellable lead lists are supported, but keep provider mechanics out of the first
|
|
@@ -168,7 +176,9 @@ artifacts are optional only.
|
|
|
168
176
|
When the user chooses filters, immediately call
|
|
169
177
|
`update_campaign({ campaignId, enableICPFilters: true, currentStep: "create-icp-rubric", watchNarration })`
|
|
170
178
|
before rubric thinking or branch work. The watched app should move to Filter
|
|
171
|
-
Rules quickly
|
|
179
|
+
Rules quickly. After `save_rubrics`, the watched app should move to
|
|
180
|
+
`apply-icp-rubric` / Filter Leads so the user can see the saved filters are
|
|
181
|
+
ready before message approval unlocks any enrichment or filtering.
|
|
172
182
|
|
|
173
183
|
Lead Fit Builder persists production rubrics with `save_rubrics` when filters
|
|
174
184
|
are enabled. It must not require `brief.md`, `lead-review.md`, or
|
|
@@ -47,14 +47,14 @@ The customer believes Sellable is helping them launch a campaign. Keep every
|
|
|
47
47
|
turn anchored to that:
|
|
48
48
|
|
|
49
49
|
1. Confirm who/what company the campaign is for.
|
|
50
|
-
2.
|
|
51
|
-
3.
|
|
52
|
-
4.
|
|
53
|
-
5. Find likely responders.
|
|
54
|
-
6.
|
|
55
|
-
7.
|
|
56
|
-
8. Ask for approval.
|
|
57
|
-
9.
|
|
50
|
+
2. Understand the company, offer, target, proof, and lead-source direction.
|
|
51
|
+
3. Turn that into a campaign brief and create the watchable campaign shell.
|
|
52
|
+
4. Ask for brief approval before any lead import or sending-adjacent work.
|
|
53
|
+
5. Find likely responders and approve the source.
|
|
54
|
+
6. Import only the bounded review batch.
|
|
55
|
+
7. Filter for fit and draft the reusable message template from the same sample.
|
|
56
|
+
8. Ask for message approval before queueing the review-batch cascade.
|
|
57
|
+
9. Use Settings for sender selection, sequence attach, and final launch handoff.
|
|
58
58
|
|
|
59
59
|
Approvals only feel safe when the user can see what they are approving. Before
|
|
60
60
|
any approve/revise question, show the relevant decision in plain language. For a
|
|
@@ -80,12 +80,13 @@ the sentence, or revise the message. It should include the exact fallback
|
|
|
80
80
|
example, like `omit the noticed... line` or `use "operators"`. Missing data
|
|
81
81
|
should never produce robotic or creepy copy.
|
|
82
82
|
|
|
83
|
-
Approved token guidance is part of the campaign, not just the review.
|
|
84
|
-
|
|
85
|
-
token fill rules and examples
|
|
83
|
+
Approved token guidance is part of the campaign, not just the review. After the
|
|
84
|
+
bounded review batch exists and message generation has a selected template, the
|
|
85
|
+
campaign brief should carry forward the token fill rules and examples before any
|
|
86
|
+
workflow-table cascade is queued: good fills, good omits, bad fills, fallback
|
|
86
87
|
rules, and why the bad fills are blocked.
|
|
87
88
|
The campaign brief must carry forward the token fill rules from review into the
|
|
88
|
-
live campaign state before
|
|
89
|
+
live campaign state before enrichment, filtering, or Generate Message cells run.
|
|
89
90
|
|
|
90
91
|
## Progress Updates
|
|
91
92
|
|
|
@@ -147,18 +148,17 @@ unless the user asks for them.
|
|
|
147
148
|
Good opening:
|
|
148
149
|
|
|
149
150
|
```text
|
|
150
|
-
I’ll help you launch this as a Sellable campaign. First I’ll
|
|
151
|
-
|
|
152
|
-
|
|
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.
|
|
153
154
|
```
|
|
154
155
|
|
|
155
156
|
Good identity setup:
|
|
156
157
|
|
|
157
158
|
```text
|
|
158
|
-
I’ll
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
keep going.
|
|
159
|
+
I’ll confirm the client/company this campaign is for before we pick the target,
|
|
160
|
+
offer, proof, and lead source. Paste a LinkedIn profile or company website and
|
|
161
|
+
I’ll resolve the campaign identity before the setup choices.
|
|
162
162
|
```
|
|
163
163
|
|
|
164
164
|
Bad:
|
|
@@ -328,11 +328,11 @@
|
|
|
328
328
|
"requiredValues": {
|
|
329
329
|
"currentStep": "pick-provider",
|
|
330
330
|
"watchNarration.stage": "find-leads",
|
|
331
|
-
"watchNarration.headline": "
|
|
332
|
-
"watchNarration.visibleState": "The browser is showing source selection.",
|
|
333
|
-
"watchNarration.agentIntent": "Codex is explaining the source lane before
|
|
334
|
-
"watchNarration.nextAction": "Approve a source
|
|
335
|
-
"watchNarration.safety": "
|
|
331
|
+
"watchNarration.headline": "Review the source plan",
|
|
332
|
+
"watchNarration.visibleState": "The browser is showing source selection before scouting starts.",
|
|
333
|
+
"watchNarration.agentIntent": "Codex is explaining the recommended campaign-specific source lane and fallback before any search runs.",
|
|
334
|
+
"watchNarration.nextAction": "Approve a scouting plan or choose another source",
|
|
335
|
+
"watchNarration.safety": "Approval here authorizes source scouting/search only; no selected-post scrape, lead import, filtering, messaging, sequence, or sending starts."
|
|
336
336
|
},
|
|
337
337
|
"purpose": "show the visible source-plan approval checkpoint before provider lanes"
|
|
338
338
|
},
|
|
@@ -354,17 +354,48 @@
|
|
|
354
354
|
"plain-language source options for this campaign",
|
|
355
355
|
"recommended first source lane",
|
|
356
356
|
"why the lane is likely to have relevant active prospects",
|
|
357
|
-
"
|
|
357
|
+
"fallback lane if the recommended lane looks weak",
|
|
358
358
|
"what scouting will check next",
|
|
359
359
|
"what approval authorizes"
|
|
360
360
|
],
|
|
361
361
|
"choices": [
|
|
362
|
-
"Approve
|
|
362
|
+
"Approve Signal Discovery scouting plan",
|
|
363
|
+
"Approve Sales Nav scouting plan",
|
|
364
|
+
"Approve Prospeo scouting plan",
|
|
363
365
|
"Choose different source",
|
|
364
366
|
"Pause here"
|
|
365
367
|
],
|
|
368
|
+
"approvalChoiceLabelsByProvider": {
|
|
369
|
+
"signal-discovery": "Approve Signal Discovery scouting plan",
|
|
370
|
+
"sales-nav": "Approve Sales Nav scouting plan",
|
|
371
|
+
"prospeo": "Approve Prospeo scouting plan"
|
|
372
|
+
},
|
|
366
373
|
"approvalState": "source_lane_approved"
|
|
367
374
|
},
|
|
375
|
+
{
|
|
376
|
+
"action": "persist_provider_search_step_before_search",
|
|
377
|
+
"tool": "update_campaign",
|
|
378
|
+
"requiredPrecondition": "source_lane_approved",
|
|
379
|
+
"providerCurrentStepMap": {
|
|
380
|
+
"signal-discovery": "signal-discovery",
|
|
381
|
+
"sales-nav": "sales-nav",
|
|
382
|
+
"prospeo": "prospeo"
|
|
383
|
+
},
|
|
384
|
+
"requiredValues": {
|
|
385
|
+
"leadSourceType": "new",
|
|
386
|
+
"leadSourceProvider": "approved provider",
|
|
387
|
+
"currentStep": "provider-specific current step",
|
|
388
|
+
"watchNarration.stage": "find-leads",
|
|
389
|
+
"watchNarration.headline": "Searching the approved source lane",
|
|
390
|
+
"watchNarration.safety": "Search/scouting only; no lead import or selected-post scrape starts from this update."
|
|
391
|
+
},
|
|
392
|
+
"mustRunBefore": [
|
|
393
|
+
"search_signals",
|
|
394
|
+
"search_sales_nav",
|
|
395
|
+
"search_prospeo",
|
|
396
|
+
"fetch_post_engagers"
|
|
397
|
+
]
|
|
398
|
+
},
|
|
368
399
|
{
|
|
369
400
|
"action": "run_sequential_source_funnel",
|
|
370
401
|
"requiredPrecondition": "source_lane_approved",
|
|
@@ -428,6 +459,9 @@
|
|
|
428
459
|
"action": "show_source_decision_card",
|
|
429
460
|
"requiredInlineFields": [
|
|
430
461
|
"primary source and exact filters/recipe",
|
|
462
|
+
"specific source action awaiting approval",
|
|
463
|
+
"for Signal Discovery: selected post count and target engager/source-candidate volume",
|
|
464
|
+
"bounded review batch size",
|
|
431
465
|
"runner-up and why it lost",
|
|
432
466
|
"raw volume",
|
|
433
467
|
"sampled people",
|
|
@@ -441,10 +475,16 @@
|
|
|
441
475
|
"action": "ask_source_review_choice",
|
|
442
476
|
"uses": "request_user_input",
|
|
443
477
|
"choices": [
|
|
444
|
-
"
|
|
478
|
+
"Scrape selected posts for the bounded review batch",
|
|
479
|
+
"Run the approved source import for the bounded review batch",
|
|
445
480
|
"Revise source",
|
|
446
481
|
"Pause here"
|
|
447
|
-
]
|
|
482
|
+
],
|
|
483
|
+
"approvalChoiceLabelsByProvider": {
|
|
484
|
+
"signal-discovery": "Scrape selected posts for the bounded review batch",
|
|
485
|
+
"sales-nav": "Import the approved Sales Nav review batch",
|
|
486
|
+
"prospeo": "Import the approved Prospeo review batch"
|
|
487
|
+
}
|
|
448
488
|
}
|
|
449
489
|
],
|
|
450
490
|
"requiredCampaignState": [
|
|
@@ -683,7 +723,12 @@
|
|
|
683
723
|
"campaignOfferId",
|
|
684
724
|
"leadScoringRubrics"
|
|
685
725
|
],
|
|
686
|
-
"writesCampaignState": "leadScoringRubrics"
|
|
726
|
+
"writesCampaignState": "leadScoringRubrics",
|
|
727
|
+
"requiredSideEffects": {
|
|
728
|
+
"enableICPFilters": true,
|
|
729
|
+
"currentStep": "apply-icp-rubric",
|
|
730
|
+
"watchNarration.headline": "Filter Leads is ready"
|
|
731
|
+
}
|
|
687
732
|
}
|
|
688
733
|
],
|
|
689
734
|
"requiredCampaignState": [
|
|
@@ -722,6 +767,10 @@
|
|
|
722
767
|
"revise_rubric",
|
|
723
768
|
"revise_messaging"
|
|
724
769
|
],
|
|
770
|
+
"hardRules": [
|
|
771
|
+
"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"
|
|
773
|
+
],
|
|
725
774
|
"transitions": {
|
|
726
775
|
"post_lead_workstreams_ready": "message-review",
|
|
727
776
|
"revise_leads": "find-leads",
|
|
@@ -747,7 +796,12 @@
|
|
|
747
796
|
"campaignOfferId",
|
|
748
797
|
"leadScoringRubrics"
|
|
749
798
|
],
|
|
750
|
-
"writesCampaignState": "leadScoringRubrics"
|
|
799
|
+
"writesCampaignState": "leadScoringRubrics",
|
|
800
|
+
"requiredSideEffects": {
|
|
801
|
+
"enableICPFilters": true,
|
|
802
|
+
"currentStep": "apply-icp-rubric",
|
|
803
|
+
"watchNarration.headline": "Filter Leads is ready"
|
|
804
|
+
}
|
|
751
805
|
}
|
|
752
806
|
],
|
|
753
807
|
"requiredCampaignState": [
|
|
@@ -214,7 +214,9 @@ and do not say filtering the batch before rubrics and message approval are
|
|
|
214
214
|
saved. Only show worker statuses as running if those branches actually started.
|
|
215
215
|
When the user chooses filters, immediately persist `enableICPFilters: true` and
|
|
216
216
|
move to `create-icp-rubric` so the watched app shows Filter Rules while Codex
|
|
217
|
-
defines the rules in chat.
|
|
217
|
+
defines the rules in chat. After `save_rubrics`, move to `apply-icp-rubric`
|
|
218
|
+
so the watched app shows Filter Leads with saved rules before message approval
|
|
219
|
+
unlocks any enrichment or filtering.
|
|
218
220
|
|
|
219
221
|
Fit + message:
|
|
220
222
|
|
|
@@ -132,9 +132,9 @@ The kickoff doc is the resume surface. Re-open it before repeating discovery wor
|
|
|
132
132
|
- Before the first provider prompt, search, source scout, or signal-discovery
|
|
133
133
|
call, show the user a compact source plan and get approval. The plan must say
|
|
134
134
|
which campaign-specific options are plausible, which lane you recommend
|
|
135
|
-
first,
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
first, the exact evidence you expect to test for this ICP/offer, what
|
|
136
|
+
fallback lane you will use if the evidence is thin, and that approval
|
|
137
|
+
authorizes scouting/search only.
|
|
138
138
|
- When enough context exists, try 1-2 alternate hypotheses if the first lane is too weak or noisy.
|
|
139
139
|
- Directional preview does not require a sender, campaign, or selected lead list. Start with count/sample exploration first; only attach searches to a campaign when the user is ready to import.
|
|
140
140
|
- If the user already has a LinkedIn-profile CSV, treat that as a direct lead-list path and skip discovery.
|