@sellable/mcp 0.1.139 → 0.1.140
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/dist/tools/navigation.js +0 -3
- package/dist/tools/processing.d.ts +1 -0
- package/dist/tools/prompts.js +1 -1
- package/dist/tools/rubrics.d.ts +2 -0
- package/dist/tools/rubrics.js +57 -10
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +28 -5
- package/skills/create-campaign-v2/SKILL.md +25 -0
- package/skills/create-campaign-v2/SOUL.md +8 -0
- package/skills/create-campaign-v2/core/flow.v2.json +84 -7
- package/skills/create-campaign-v2/references/watch-guide-narration.md +2 -2
- package/skills/find-leads/SKILL.md +6 -0
package/dist/index-dev.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/tools/navigation.js
CHANGED
|
@@ -243,9 +243,6 @@ function checkMessages(campaign) {
|
|
|
243
243
|
if (!hasApprovedMessageTemplate(campaign)) {
|
|
244
244
|
missing.push("approvedMessageTemplate");
|
|
245
245
|
}
|
|
246
|
-
if (campaign.currentStep === "auto-execute-messaging") {
|
|
247
|
-
missing.push("generatedMessageReview");
|
|
248
|
-
}
|
|
249
246
|
return { stepId: "messages", missing };
|
|
250
247
|
}
|
|
251
248
|
function checkSettings(campaign) {
|
|
@@ -58,6 +58,7 @@ export declare function upsertRubric(input: UpsertRubricInput): Promise<{
|
|
|
58
58
|
export type CampaignRubricsResponse = {
|
|
59
59
|
campaignOfferId: string;
|
|
60
60
|
enableICPFilters: boolean | null;
|
|
61
|
+
currentStep?: string | null;
|
|
61
62
|
workflowTableId: string | null;
|
|
62
63
|
rubrics: RubricItem[];
|
|
63
64
|
};
|
package/dist/tools/prompts.js
CHANGED
|
@@ -341,7 +341,7 @@ export function getPostFindLeadsScoutRegistry() {
|
|
|
341
341
|
usage: {
|
|
342
342
|
codex: "After the user approves or auto-confirms the lead source, spawn both returned scout `name` values in one assistant turn only when the current Codex host exposes those custom agents.",
|
|
343
343
|
claude: "After lead source approval, invoke both returned Task/Agent subagents in one assistant message only when the current Claude session lists those agents, so filter-leads and message generation run concurrently.",
|
|
344
|
-
parentThreadRule: "Named agents are optional acceleration. If they are absent, do not customer-surface install status; the main thread still orchestrates filter and message branches from CampaignOffer state, selected source state, workflowTableId, and imported review-batch rows. Local markdown/json files are not normal-path inputs. The message branch must load the full generate-messages prompt, must read live campaign/review-batch state through scoped MCP/product tools, must reject mismatched selectedLeadListId/workflowTableId/campaign/workspace input
|
|
344
|
+
parentThreadRule: "Named agents are optional acceleration. If they are absent, do not customer-surface install status; the main thread still orchestrates filter and message branches from CampaignOffer state, selected source state, workflowTableId, and imported review-batch rows. Local markdown/json files are not normal-path inputs. The message drafting branch must load the full generate-messages prompt, must read live campaign/review-batch state through scoped MCP/product tools, and must reject mismatched selectedLeadListId/workflowTableId/campaign/workspace input. Template approval in the parent thread uses the create-campaign-v2 message-review safety gate; do not load the full generate-messages prompt for approval-only review. Join before message review. Do not automatically rerun Message Draft Builder after filters/enrichment finish; show the initial draft by default and offer an enriched rewrite only with explicit user opt-in.",
|
|
345
345
|
},
|
|
346
346
|
};
|
|
347
347
|
}
|
package/dist/tools/rubrics.d.ts
CHANGED
|
@@ -481,6 +481,8 @@ export declare function saveRubrics(input: SaveRubricsInput): Promise<{
|
|
|
481
481
|
criteriaCount: number;
|
|
482
482
|
deletedCount: number;
|
|
483
483
|
enableICPFiltersSet: boolean;
|
|
484
|
+
currentStep: string | null;
|
|
485
|
+
currentStepSet: boolean;
|
|
484
486
|
rubrics: RubricItem[];
|
|
485
487
|
activeRubrics: RubricItem[];
|
|
486
488
|
}>;
|
package/dist/tools/rubrics.js
CHANGED
|
@@ -85,9 +85,39 @@ async function fetchCampaignOffer(campaignOfferId) {
|
|
|
85
85
|
return {
|
|
86
86
|
workflowTableId: v3.workflowTableId,
|
|
87
87
|
enableICPFilters: v3.enableICPFilters,
|
|
88
|
+
currentStep: v3.currentStep,
|
|
88
89
|
leadScoringRubrics: v3.rubrics,
|
|
89
90
|
};
|
|
90
91
|
}
|
|
92
|
+
const filterRulesEntryWatchNarration = {
|
|
93
|
+
stage: "fit-message",
|
|
94
|
+
headline: "Create filter rules",
|
|
95
|
+
visibleState: "Filters are enabled and the browser is showing Filter Rules while the rubric is saved.",
|
|
96
|
+
agentIntent: "Codex is defining fit rules before any enrichment, filtering, or message cells run.",
|
|
97
|
+
nextAction: "Review saved filter rules",
|
|
98
|
+
progressLabel: "Fit + message",
|
|
99
|
+
safety: "No enrichment, filtering, Generate Message cells, sequence setup, or sending starts from this step.",
|
|
100
|
+
};
|
|
101
|
+
function shouldMoveToFilterRules(currentStep) {
|
|
102
|
+
if (!currentStep)
|
|
103
|
+
return true;
|
|
104
|
+
return [
|
|
105
|
+
"confirm-lead-list",
|
|
106
|
+
"filter-choice",
|
|
107
|
+
"create-icp-rubric",
|
|
108
|
+
"filter-rules",
|
|
109
|
+
].includes(currentStep);
|
|
110
|
+
}
|
|
111
|
+
function buildEnableIcpFiltersPayload(currentStep) {
|
|
112
|
+
const payload = {
|
|
113
|
+
enableICPFilters: true,
|
|
114
|
+
};
|
|
115
|
+
if (shouldMoveToFilterRules(currentStep)) {
|
|
116
|
+
payload.currentStep = "create-icp-rubric";
|
|
117
|
+
payload.watchNarration = filterRulesEntryWatchNarration;
|
|
118
|
+
}
|
|
119
|
+
return payload;
|
|
120
|
+
}
|
|
91
121
|
async function getRubricsForEdit(campaignOfferId) {
|
|
92
122
|
const draft = getDraftRubrics(campaignOfferId);
|
|
93
123
|
if (draft) {
|
|
@@ -204,7 +234,7 @@ export const rubricToolDefinitions = [
|
|
|
204
234
|
},
|
|
205
235
|
{
|
|
206
236
|
name: "save_rubrics",
|
|
207
|
-
description: "Persist rubric criteria to the campaign. Pass leadScoringRubrics directly to save without drafting. Saving active rubrics enables ICP filtering
|
|
237
|
+
description: "Persist rubric criteria to the campaign. Pass leadScoringRubrics directly to save without drafting. Saving active rubrics enables ICP filtering and keeps/moves the watched client to Filter Rules; it does not apply Filter Leads by itself.",
|
|
208
238
|
inputSchema: {
|
|
209
239
|
type: "object",
|
|
210
240
|
properties: {
|
|
@@ -534,26 +564,43 @@ export async function saveRubrics(input) {
|
|
|
534
564
|
// column cells=false → ICP Score runCondition evaluated false → entire
|
|
535
565
|
// cascade blocked.
|
|
536
566
|
let enableICPFiltersSet = false;
|
|
567
|
+
let currentStepSet = false;
|
|
537
568
|
try {
|
|
538
569
|
const api = getApi();
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
});
|
|
570
|
+
const payload = buildEnableIcpFiltersPayload(campaign.currentStep);
|
|
571
|
+
await api.put(`/api/v2/campaign-offers/${input.campaignOfferId}`, payload);
|
|
542
572
|
enableICPFiltersSet = true;
|
|
573
|
+
currentStepSet = payload.currentStep === "create-icp-rubric";
|
|
543
574
|
}
|
|
544
575
|
catch (error) {
|
|
545
|
-
// Non-fatal: the rubric save already succeeded.
|
|
546
|
-
//
|
|
547
|
-
|
|
576
|
+
// Non-fatal: the rubric save already succeeded. Retry the minimum
|
|
577
|
+
// enablement payload in case a stale step beat was rejected.
|
|
578
|
+
try {
|
|
579
|
+
const api = getApi();
|
|
580
|
+
await api.put(`/api/v2/campaign-offers/${input.campaignOfferId}`, {
|
|
581
|
+
enableICPFilters: true,
|
|
582
|
+
});
|
|
583
|
+
enableICPFiltersSet = true;
|
|
584
|
+
console.warn("[save_rubrics] Enabled ICP filtering without moving currentStep", input.campaignOfferId, error);
|
|
585
|
+
}
|
|
586
|
+
catch (fallbackError) {
|
|
587
|
+
console.error("[save_rubrics] Could not auto-enable ICP filtering on campaign", input.campaignOfferId, fallbackError);
|
|
588
|
+
}
|
|
548
589
|
}
|
|
549
590
|
return {
|
|
550
591
|
success: true,
|
|
551
|
-
message:
|
|
552
|
-
? `Saved ${normalizedDraft.length} rubric criteria
|
|
553
|
-
:
|
|
592
|
+
message: currentStepSet
|
|
593
|
+
? `Saved ${normalizedDraft.length} rubric criteria, ICP filtering is ON, and the campaign is on Filter Rules.`
|
|
594
|
+
: enableICPFiltersSet || campaign.enableICPFilters === true
|
|
595
|
+
? `Saved ${normalizedDraft.length} rubric criteria and ICP filtering is ON.`
|
|
596
|
+
: `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.`,
|
|
554
597
|
criteriaCount: normalizedDraft.length,
|
|
555
598
|
deletedCount: deletedRubricIds.length,
|
|
556
599
|
enableICPFiltersSet,
|
|
600
|
+
currentStep: currentStepSet
|
|
601
|
+
? "create-icp-rubric"
|
|
602
|
+
: (campaign.currentStep ?? null),
|
|
603
|
+
currentStepSet,
|
|
557
604
|
rubrics: result?.rubrics ?? normalizedDraft,
|
|
558
605
|
activeRubrics: result?.rubrics ?? normalizedDraft,
|
|
559
606
|
};
|
package/package.json
CHANGED
|
@@ -117,6 +117,25 @@ data, compare sources by source volume, sampled ICP fit, activity/warmth
|
|
|
117
117
|
signals, cleanup risk, and confidence basis. If a user asks for a forecast,
|
|
118
118
|
label it explicitly as not estimated from this run.
|
|
119
119
|
|
|
120
|
+
Before any provider prompt, search, source scout, or signal-discovery call,
|
|
121
|
+
show a short source-plan gate and ask for approval. The gate should say:
|
|
122
|
+
|
|
123
|
+
- given this campaign, the viable source options
|
|
124
|
+
- the recommended first lane
|
|
125
|
+
- why that lane fits the buyer, offer, and likely public activity
|
|
126
|
+
- what will be tested next
|
|
127
|
+
- the fallback lane if relevant posts or ICP engagement look thin
|
|
128
|
+
- that approval authorizes scouting/search only, not lead import or sending
|
|
129
|
+
|
|
130
|
+
If active prospects likely engage with relevant LinkedIn content, recommend
|
|
131
|
+
LinkedIn post engagement / Signal Discovery and name the post themes you will
|
|
132
|
+
look for. If the niche is too private, low-volume, or unlikely to have relevant
|
|
133
|
+
public posts, recommend Sales Nav recent activity, broader Sales Nav role/title
|
|
134
|
+
filters, or Prospeo, and explain the tradeoff. Do not call `search_signals`,
|
|
135
|
+
`search_sales_nav`, `search_prospeo`, `fetch_post_engagers`, or provider-scoped
|
|
136
|
+
subagents until the user approves this source plan or explicitly chooses a
|
|
137
|
+
different source.
|
|
138
|
+
|
|
120
139
|
When the user has not supplied a source and multiple source angles are viable,
|
|
121
140
|
scout those angles as independent branches when the host can actually do it:
|
|
122
141
|
LinkedIn Engagement / active post engagers (internal `signal-discovery`
|
|
@@ -577,9 +596,12 @@ updates.
|
|
|
577
596
|
queue workflow cells, attach a sequence, or start until the filter choice is
|
|
578
597
|
resolved, rubrics are saved when filters are enabled, template/token rules
|
|
579
598
|
are approved on the default Use Template path, and the approved message set
|
|
580
|
-
is synced into the campaign brief.
|
|
581
|
-
|
|
582
|
-
|
|
599
|
+
is synced into the campaign brief. When filters are approved, immediately
|
|
600
|
+
call `mcp__sellable__update_campaign({ campaignId, enableICPFilters: true, currentStep: "create-icp-rubric", watchNarration })`
|
|
601
|
+
so the watched app moves to Filter Rules while rubrics are drafted/saved.
|
|
602
|
+
After rubrics save, pause and say the fit rules are saved; approve the
|
|
603
|
+
message template next; after approval, queue the bounded review-batch
|
|
604
|
+
`enrichCellId` cells to kick off enrichment/filtering.
|
|
583
605
|
Product Generate Message cells must not run from the background template
|
|
584
606
|
path before that template/token approval.
|
|
585
607
|
Do not ask the user to approve the brief before shell creation unless they
|
|
@@ -588,8 +610,9 @@ updates.
|
|
|
588
610
|
`mcp__sellable__update_campaign({ campaignId, currentStep })` before major
|
|
589
611
|
visible work so the user can watch progress in the app: `create-offer` for
|
|
590
612
|
the brief, `pick-provider` or the selected provider step while sourcing,
|
|
591
|
-
`filter-choice` after the 15-row review batch, `
|
|
592
|
-
|
|
613
|
+
`filter-choice` after the 15-row review batch, `create-icp-rubric` as soon
|
|
614
|
+
as filters are approved, `messages` for the Use Template / AI Generated mode
|
|
615
|
+
choice, `auto-execute-messaging` for approved
|
|
593
616
|
message work or the product's AI-generated path, `awaiting-user-greenlight`
|
|
594
617
|
for the final handoff, `settings` for sender selection, `sequence` after
|
|
595
618
|
sender attach, and `send` once the recommended sequence is attached.
|
|
@@ -122,6 +122,26 @@ Default source order when the user has not supplied a source:
|
|
|
122
122
|
3. broader Sales Nav role/title filters
|
|
123
123
|
4. Prospeo account/contact expansion
|
|
124
124
|
|
|
125
|
+
Before any provider prompt, search, source scout, or signal-discovery call,
|
|
126
|
+
show a short source-plan gate and ask for approval. The gate must say, in plain
|
|
127
|
+
language:
|
|
128
|
+
|
|
129
|
+
- given this campaign, the viable source options
|
|
130
|
+
- the recommended first lane
|
|
131
|
+
- why that lane fits the buyer, offer, and likely public activity
|
|
132
|
+
- what will be tested next
|
|
133
|
+
- the fallback lane if relevant posts or ICP engagement look thin
|
|
134
|
+
- that approval authorizes scouting/search only, not lead import or sending
|
|
135
|
+
|
|
136
|
+
If active prospects likely engage with relevant LinkedIn content, recommend
|
|
137
|
+
LinkedIn post engagement / Signal Discovery and name the post themes you will
|
|
138
|
+
look for. If the niche is too private, low-volume, or unlikely to have relevant
|
|
139
|
+
public posts, recommend Sales Nav recent activity, broader Sales Nav role/title
|
|
140
|
+
filters, or Prospeo, and explain the tradeoff. Do not call `search_signals`,
|
|
141
|
+
`search_sales_nav`, `search_prospeo`, `fetch_post_engagers`, or provider-scoped
|
|
142
|
+
subagents until the user approves this source plan or explicitly chooses a
|
|
143
|
+
different source.
|
|
144
|
+
|
|
125
145
|
Call `get_source_scout_registry` before source scouting. Source scouting is
|
|
126
146
|
sequential by default. Run `source-scout-linkedin-engagement`,
|
|
127
147
|
`source-scout-sales-nav`, and `source-scout-prospeo-contact` in parallel only
|
|
@@ -145,6 +165,11 @@ After `confirm_lead_list` imports a non-empty bounded review batch and
|
|
|
145
165
|
CampaignOffer/source/table state as the source of truth. Debug markdown/json
|
|
146
166
|
artifacts are optional only.
|
|
147
167
|
|
|
168
|
+
When the user chooses filters, immediately call
|
|
169
|
+
`update_campaign({ campaignId, enableICPFilters: true, currentStep: "create-icp-rubric", watchNarration })`
|
|
170
|
+
before rubric thinking or branch work. The watched app should move to Filter
|
|
171
|
+
Rules quickly, then show the saved rubric there after `save_rubrics`.
|
|
172
|
+
|
|
148
173
|
Lead Fit Builder persists production rubrics with `save_rubrics` when filters
|
|
149
174
|
are enabled. It must not require `brief.md`, `lead-review.md`, or
|
|
150
175
|
`lead-sample.json`.
|
|
@@ -228,6 +228,14 @@ setting: `~/.codex/config.toml` with
|
|
|
228
228
|
|
|
229
229
|
## Approval Ethic
|
|
230
230
|
|
|
231
|
+
Lead sourcing has two approvals. First, before any provider prompt/search/scout
|
|
232
|
+
call, give the user a compact source plan: "given this campaign, these are the
|
|
233
|
+
real options, I recommend this first lane, here is why, here is the fallback if
|
|
234
|
+
the evidence is thin." Ask them to approve that plan or choose a different
|
|
235
|
+
source. That approval only authorizes scouting/search. Second, after the
|
|
236
|
+
source evidence exists, show counts, samples, fit math, cleanup risk, and ask
|
|
237
|
+
for source approval before import.
|
|
238
|
+
|
|
231
239
|
## Parallelism + Naming
|
|
232
240
|
|
|
233
241
|
Source selection is sequential by default. Start with the first recommended
|
|
@@ -283,6 +283,27 @@
|
|
|
283
283
|
"id": "find-leads",
|
|
284
284
|
"label": "Find leads",
|
|
285
285
|
"sourceSelectionFunnel": {
|
|
286
|
+
"preScoutRecommendationGate": {
|
|
287
|
+
"required": true,
|
|
288
|
+
"label": "Source plan approval",
|
|
289
|
+
"mustHappenBefore": [
|
|
290
|
+
"get_provider_prompt",
|
|
291
|
+
"search_signals",
|
|
292
|
+
"search_sales_nav",
|
|
293
|
+
"search_prospeo",
|
|
294
|
+
"fetch_post_engagers",
|
|
295
|
+
"source-scout dispatch"
|
|
296
|
+
],
|
|
297
|
+
"show": [
|
|
298
|
+
"campaign-specific options considered",
|
|
299
|
+
"recommended first lane",
|
|
300
|
+
"why this lane matches the offer and ICP",
|
|
301
|
+
"expected evidence to gather",
|
|
302
|
+
"fallback lane if the first lane is weak",
|
|
303
|
+
"what approval authorizes"
|
|
304
|
+
],
|
|
305
|
+
"approvalAuthorizes": "source scouting/search only; no lead import, review-batch creation, filtering, messaging, sequence, or launch"
|
|
306
|
+
},
|
|
286
307
|
"defaultWhenSourceUnspecified": [
|
|
287
308
|
"signal-discovery",
|
|
288
309
|
"sales-nav-recent-active",
|
|
@@ -306,16 +327,47 @@
|
|
|
306
327
|
"tool": "update_campaign",
|
|
307
328
|
"requiredValues": {
|
|
308
329
|
"currentStep": "pick-provider",
|
|
309
|
-
"watchNarration.stage": "find-leads"
|
|
330
|
+
"watchNarration.stage": "find-leads",
|
|
331
|
+
"watchNarration.headline": "Choose the first source",
|
|
332
|
+
"watchNarration.visibleState": "The browser is showing source selection.",
|
|
333
|
+
"watchNarration.agentIntent": "Codex is explaining the source lane before sampling leads.",
|
|
334
|
+
"watchNarration.nextAction": "Approve a source lane",
|
|
335
|
+
"watchNarration.safety": "No leads import until a source is approved."
|
|
310
336
|
},
|
|
311
|
-
"purpose": "show the visible source-
|
|
337
|
+
"purpose": "show the visible source-plan approval checkpoint before provider lanes"
|
|
312
338
|
},
|
|
313
339
|
{
|
|
314
340
|
"tool": "get_source_scout_registry",
|
|
315
341
|
"purpose": "load canonical source scout names before optional branch launch"
|
|
316
342
|
},
|
|
343
|
+
{
|
|
344
|
+
"action": "show_pre_scout_source_recommendation",
|
|
345
|
+
"uses": "request_user_input",
|
|
346
|
+
"requiredBeforeTools": [
|
|
347
|
+
"get_provider_prompt",
|
|
348
|
+
"search_signals",
|
|
349
|
+
"search_sales_nav",
|
|
350
|
+
"search_prospeo",
|
|
351
|
+
"fetch_post_engagers"
|
|
352
|
+
],
|
|
353
|
+
"requiredInlineFields": [
|
|
354
|
+
"plain-language source options for this campaign",
|
|
355
|
+
"recommended first source lane",
|
|
356
|
+
"why the lane is likely to have relevant active prospects",
|
|
357
|
+
"why a database/recent-activity fallback may be better if niche conversations are thin",
|
|
358
|
+
"what scouting will check next",
|
|
359
|
+
"what approval authorizes"
|
|
360
|
+
],
|
|
361
|
+
"choices": [
|
|
362
|
+
"Approve recommended source",
|
|
363
|
+
"Choose different source",
|
|
364
|
+
"Pause here"
|
|
365
|
+
],
|
|
366
|
+
"approvalState": "source_lane_approved"
|
|
367
|
+
},
|
|
317
368
|
{
|
|
318
369
|
"action": "run_sequential_source_funnel",
|
|
370
|
+
"requiredPrecondition": "source_lane_approved",
|
|
319
371
|
"defaultOrder": [
|
|
320
372
|
"source-scout-linkedin-engagement",
|
|
321
373
|
"source-scout-sales-nav",
|
|
@@ -532,7 +584,7 @@
|
|
|
532
584
|
"tool": "update_campaign",
|
|
533
585
|
"requiredValues": {
|
|
534
586
|
"currentStep": "filter-choice",
|
|
535
|
-
"watchNarration.stage": "
|
|
587
|
+
"watchNarration.stage": "fit-message"
|
|
536
588
|
}
|
|
537
589
|
},
|
|
538
590
|
{
|
|
@@ -581,6 +633,30 @@
|
|
|
581
633
|
"id": "post-lead-workstreams",
|
|
582
634
|
"label": "Filter and message workstreams",
|
|
583
635
|
"onEnter": [
|
|
636
|
+
{
|
|
637
|
+
"action": "persist_add_filters_approval",
|
|
638
|
+
"tool": "update_campaign",
|
|
639
|
+
"when": "filters_enabled",
|
|
640
|
+
"requiredFields": [
|
|
641
|
+
"campaignId",
|
|
642
|
+
"enableICPFilters",
|
|
643
|
+
"currentStep",
|
|
644
|
+
"watchNarration"
|
|
645
|
+
],
|
|
646
|
+
"requiredValues": {
|
|
647
|
+
"enableICPFilters": true,
|
|
648
|
+
"currentStep": "create-icp-rubric",
|
|
649
|
+
"watchNarration.stage": "fit-message",
|
|
650
|
+
"watchNarration.headline": "Create filter rules",
|
|
651
|
+
"watchNarration.visibleState": "Filters are enabled and the browser is showing Filter Rules while Codex defines the rubric.",
|
|
652
|
+
"watchNarration.nextAction": "Review saved filter rules"
|
|
653
|
+
},
|
|
654
|
+
"mustRunBefore": [
|
|
655
|
+
"get_post_find_leads_scout_registry",
|
|
656
|
+
"launch_or_reuse_post_lead_workstreams",
|
|
657
|
+
"save_rubrics"
|
|
658
|
+
]
|
|
659
|
+
},
|
|
584
660
|
{
|
|
585
661
|
"tool": "get_post_find_leads_scout_registry",
|
|
586
662
|
"purpose": "load canonical post-lead worker names"
|
|
@@ -716,7 +792,7 @@
|
|
|
716
792
|
"target": "post-find-leads-message-scout",
|
|
717
793
|
"toolCallRequiredBeforeDraft": [
|
|
718
794
|
"get_subskill_prompt({ subskillName: \"generate-messages\", offset, limit }) until hasMore=false",
|
|
719
|
-
"
|
|
795
|
+
"for approval-only parent-thread review, use get_subskill_asset({ subskillName: \"create-campaign-v2\", assetPath: \"references/message-review-safety-gate.md\" }) instead of loading generate-messages"
|
|
720
796
|
],
|
|
721
797
|
"stateSource": "campaignBrief, selected source state, selectedLeadListId, workflowTableId, bounded review-batch row ids/hash",
|
|
722
798
|
"outputState": "messageDraftRecommendation"
|
|
@@ -737,7 +813,7 @@
|
|
|
737
813
|
"request_user_input"
|
|
738
814
|
],
|
|
739
815
|
"toolRules": [
|
|
740
|
-
"Before message
|
|
816
|
+
"Before message drafting, the Message Draft Builder branch loads the full get_subskill_prompt({ subskillName: \"generate-messages\" }) prompt and drafts from campaignBrief, selected source state, selectedLeadListId, workflowTableId, and imported review-batch rows. For approval-only parent-thread template review, load references/message-review-safety-gate.md and do not load the full generate-messages prompt.",
|
|
741
817
|
"Do not use brief.md, lead-review.md, or lead-sample.json as required live state; those files are optional debug context only.",
|
|
742
818
|
"The compact messageDraftRecommendation must return templateRecommendation, tokenFillRules, renderedSample, concerns, status, basisToken, outputAt, outputHash, and error or retry detail.",
|
|
743
819
|
"If campaign/source/table/review-batch basis does not match, classify the output stale or blocked."
|
|
@@ -838,14 +914,15 @@
|
|
|
838
914
|
"revise_messaging"
|
|
839
915
|
],
|
|
840
916
|
"transitions": {
|
|
841
|
-
"message_approved": "
|
|
917
|
+
"message_approved": "auto-execute-messaging",
|
|
842
918
|
"revise_messaging": "message-generation"
|
|
843
919
|
}
|
|
844
920
|
},
|
|
845
921
|
{
|
|
846
922
|
"id": "validate-sample",
|
|
847
|
-
"label": "Validate bounded review batch",
|
|
923
|
+
"label": "Validate bounded review batch (legacy)",
|
|
848
924
|
"currentStepValue": "validate-sample",
|
|
925
|
+
"legacyOnly": true,
|
|
849
926
|
"reference": "references/sample-validation-loop.md",
|
|
850
927
|
"onEnter": [
|
|
851
928
|
{
|
|
@@ -251,8 +251,8 @@ Messages waiting for template:
|
|
|
251
251
|
{
|
|
252
252
|
"stage": "review-ready",
|
|
253
253
|
"headline": "Waiting for the template",
|
|
254
|
-
"visibleState": "The fit rules are saved and the
|
|
255
|
-
"agentIntent": "Codex is waiting
|
|
254
|
+
"visibleState": "The fit rules are saved and the message template is still being prepared.",
|
|
255
|
+
"agentIntent": "Codex is waiting until the template can be reviewed.",
|
|
256
256
|
"nextAction": "Review template",
|
|
257
257
|
"safety": "No enrichment, filtering, or Generate Message cells run until the template is approved."
|
|
258
258
|
}
|
|
@@ -129,6 +129,12 @@ The kickoff doc is the resume surface. Re-open it before repeating discovery wor
|
|
|
129
129
|
- Default source order for reply-likelihood-first outbound is `Signals -> Sales Nav -> Prospeo` unless the ask explicitly points elsewhere.
|
|
130
130
|
- If the user is explicit about the goal, route from that goal first.
|
|
131
131
|
- If the user is not explicit, infer the first hypothesis from the brief, then validate it with sample probes before recommending a lane.
|
|
132
|
+
- Before the first provider prompt, search, source scout, or signal-discovery
|
|
133
|
+
call, show the user a compact source plan and get approval. The plan must say
|
|
134
|
+
which campaign-specific options are plausible, which lane you recommend
|
|
135
|
+
first, why active LinkedIn engagers are or are not likely to exist for this
|
|
136
|
+
ICP/offer, what fallback lane you will use if the evidence is thin, and that
|
|
137
|
+
approval authorizes scouting/search only.
|
|
132
138
|
- When enough context exists, try 1-2 alternate hypotheses if the first lane is too weak or noisy.
|
|
133
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.
|
|
134
140
|
- If the user already has a LinkedIn-profile CSV, treat that as a direct lead-list path and skip discovery.
|