@sellable/mcp 0.1.337 → 0.1.338
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/server.js +3 -8
- package/dist/tools/campaign-refill-state.d.ts +25 -0
- package/dist/tools/campaign-refill-state.js +32 -0
- package/dist/tools/prompts.d.ts +3 -3
- package/dist/tools/prompts.js +2 -1
- package/dist/tools/registry.d.ts +2 -78
- package/dist/tools/registry.js +2 -2
- package/package.json +1 -1
- package/skills/create-campaign/SKILL.md +29 -38
- package/skills/fill-send-horizon/SKILL.md +18 -79
- package/skills/refill-sends/SKILL.md +38 -41
- package/skills/refill-sends-workflow/SKILL.md +172 -0
package/dist/server.js
CHANGED
|
@@ -9,7 +9,7 @@ import { prepareCampaignAbTest } from "./tools/campaign-ab-test.js";
|
|
|
9
9
|
import { resolveCampaignFillRoute } from "./tools/campaign-fill-routing.js";
|
|
10
10
|
import { fillCampaignHorizon } from "./tools/campaign-horizon-fill.js";
|
|
11
11
|
import { cancelPrepareCampaignMessages, getPrepareCampaignMessagesStatus, startPrepareCampaignMessages, } from "./tools/campaign-message-preparation.js";
|
|
12
|
-
import {
|
|
12
|
+
import { getCampaignRefillState } from "./tools/campaign-refill-state.js";
|
|
13
13
|
import { getCampaignTableSchema, queueCampaignCells, recordCampaignReviewBatch, reviseMessageTemplateAndRerun, selectCampaignCells, waitForCampaignProcessing, } from "./tools/campaign-processing.js";
|
|
14
14
|
import { createCampaign, duplicateCampaign, getCampaign, getCampaignMessagesPreview, getCampaigns, pauseCampaign, startCampaign, updateCampaign, updateCampaignBrief, } from "./tools/campaigns.js";
|
|
15
15
|
import { queueCells, updateCell } from "./tools/cells.js";
|
|
@@ -184,13 +184,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
184
184
|
case "resolve_campaign_fill_route":
|
|
185
185
|
result = await resolveCampaignFillRoute(args);
|
|
186
186
|
break;
|
|
187
|
-
case "
|
|
188
|
-
result = await
|
|
189
|
-
if (args?.mode === "apply" && Array.isArray(result?.appliedCampaignIds)) {
|
|
190
|
-
for (const campaignId of result.appliedCampaignIds) {
|
|
191
|
-
markCampaignContextDirty(campaignId, "refill_campaign_sends");
|
|
192
|
-
}
|
|
193
|
-
}
|
|
187
|
+
case "get_campaign_refill_state":
|
|
188
|
+
result = await getCampaignRefillState(args);
|
|
194
189
|
break;
|
|
195
190
|
case "fill_campaign_horizon":
|
|
196
191
|
result = await fillCampaignHorizon(args);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type GetCampaignRefillStateInput = {
|
|
2
|
+
campaignId?: string;
|
|
3
|
+
tableId?: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const campaignRefillStateToolDefinitions: {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: string;
|
|
10
|
+
properties: {
|
|
11
|
+
campaignId: {
|
|
12
|
+
type: string;
|
|
13
|
+
description: string;
|
|
14
|
+
};
|
|
15
|
+
tableId: {
|
|
16
|
+
type: string;
|
|
17
|
+
description: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
required: never[];
|
|
21
|
+
additionalProperties: boolean;
|
|
22
|
+
};
|
|
23
|
+
}[];
|
|
24
|
+
export declare function getCampaignRefillState(input: GetCampaignRefillStateInput): Promise<unknown>;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getApi } from "../api.js";
|
|
2
|
+
async function postCampaignRefillState(body) {
|
|
3
|
+
const api = getApi();
|
|
4
|
+
return api.post("/api/v3/mcp/campaign-refill-state", body);
|
|
5
|
+
}
|
|
6
|
+
export const campaignRefillStateToolDefinitions = [
|
|
7
|
+
{
|
|
8
|
+
name: "get_campaign_refill_state",
|
|
9
|
+
description: "read-only refill research primitive to call after resolve_campaign_fill_route and before any source import, message preparation, approval, scheduling, or horizon fill decision. It returns current campaign/table/source/sender/funnel/scheduler diagnostics plus freshness state for one exact campaignId or tableId only. This tool does not create rows, does not import leads, does not prepare messages, does not approve messages, does not schedule sends, does not launch campaigns, and does not expose direct campaign types as refillable targets. Exact targeting uses campaignId or tableId only; never pass campaign names or table names.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
campaignId: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "Optional exact CampaignOffer.id from resolve_campaign_fill_route. Do not pass campaign names.",
|
|
16
|
+
},
|
|
17
|
+
tableId: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Optional exact WorkflowTable.id from resolve_campaign_fill_route. Do not pass table names.",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: [],
|
|
23
|
+
additionalProperties: false,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
export function getCampaignRefillState(input) {
|
|
28
|
+
return postCampaignRefillState({
|
|
29
|
+
campaignId: input.campaignId,
|
|
30
|
+
tableId: input.tableId,
|
|
31
|
+
});
|
|
32
|
+
}
|
package/dist/tools/prompts.d.ts
CHANGED
|
@@ -137,7 +137,7 @@ export interface PostFindLeadsScoutRegistryResponse {
|
|
|
137
137
|
}
|
|
138
138
|
export declare const DEFAULT_SUBSKILL_PROMPT_CHUNK_CHARS = 48000;
|
|
139
139
|
export declare const MAX_SUBSKILL_PROMPT_CHUNK_CHARS = 48000;
|
|
140
|
-
export declare const ALLOWED_SUBSKILL_PROMPT_NAMES: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
|
|
140
|
+
export declare const ALLOWED_SUBSKILL_PROMPT_NAMES: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
|
|
141
141
|
export declare const promptToolDefinitions: ({
|
|
142
142
|
name: string;
|
|
143
143
|
description: string;
|
|
@@ -181,7 +181,7 @@ export declare const promptToolDefinitions: ({
|
|
|
181
181
|
properties: {
|
|
182
182
|
subskillName: {
|
|
183
183
|
type: string;
|
|
184
|
-
enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
|
|
184
|
+
enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
|
|
185
185
|
description: string;
|
|
186
186
|
};
|
|
187
187
|
offset: {
|
|
@@ -216,7 +216,7 @@ export declare const promptToolDefinitions: ({
|
|
|
216
216
|
properties: {
|
|
217
217
|
subskillName: {
|
|
218
218
|
type: string;
|
|
219
|
-
enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
|
|
219
|
+
enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
|
|
220
220
|
description: string;
|
|
221
221
|
};
|
|
222
222
|
assetPath: {
|
package/dist/tools/prompts.js
CHANGED
|
@@ -37,6 +37,7 @@ export const ALLOWED_SUBSKILL_PROMPT_NAMES = [
|
|
|
37
37
|
"interview",
|
|
38
38
|
"load-voice",
|
|
39
39
|
"refresh-sender-engagement",
|
|
40
|
+
"refill-sends-workflow",
|
|
40
41
|
"research",
|
|
41
42
|
"research-prospect",
|
|
42
43
|
"research-sender",
|
|
@@ -371,7 +372,7 @@ export function getPostFindLeadsScoutRegistry() {
|
|
|
371
372
|
codex: 'After confirm_lead_list copies source rows and the initial campaign-table execution slice exists, ask the filter-choice question immediately. Do not spawn anything before that question. After the answer, launch only Message Drafting. The filter-choice answer is the post-import user gate for this single worker; do not ask another question about starting it in step-wise or YOLO mode. The registry lookup is not a launch: after get_post_find_leads_scout_registry, immediately invoke Task/spawn_agent or the host background-agent mechanism before loading filter-leads.md, before saving rubrics, and before treating skip-filters as ready for message review. Both choices route through this kickoff; do not let filters_skipped jump straight from filter-choice to message-generation. If filters are chosen, the parent stays on Filter Rules and drafts/saves rubrics with MCP tools while Message Drafting runs in the background. If filters are skipped, move to Messages/message review only after Message Drafting has started or is ready; update_campaign(currentStep=messages) is not proof of launch. If the named Message Drafting custom agent is unavailable, spawn a generic gpt-5.5 xhigh Message Drafting background agent with the same lean campaign/table basis. When the background worker starts, persist workerDetails.messageDraftBuilder with statusSource "branch", status "branch-running", runId, startedAt, updatedAt, basisToken when known, and basis containing campaignId, selectedLeadListId, workflowTableId, filterChoice, and reviewBatchRowHash or reviewBatchRowIds; workerStatuses.messageDraftBuilder may be "running" as a simple badge only. Never put rich proof under workerStatuses and never use workerStatuses.messageDrafting. If no background-agent tool is callable, start the same full message branch inline before filter drafting or before skip-filter message review, record workerDetails.messageDraftBuilder with statusSource "parent-thread-fallback" and status "fallback-active", and require the same live context, prompt, assets, and validation gate before message review; do not wait until filters are saved and then call the registry.',
|
|
372
373
|
claude: "After confirm_lead_list copies source rows and the initial campaign-table execution slice exists, ask the filter-choice question immediately. Do not invoke any Task/Agent before that question. After the answer, invoke only Message Drafting. If filters are chosen, parent drafts/saves rubrics with MCP tools while Message Drafting runs, asks filter approval, then joins Message Drafting. If filters are skipped, invoke only Message Drafting and move to Messages/message review.",
|
|
373
374
|
parentThreadRule: 'Named agents are optional acceleration, but message drafting is not optional. The only normal background worker is Message Drafting. The filter-choice answer is the campaign-scoped go-ahead for this single post-import worker; do not ask another question to start it in step-wise or YOLO mode. If a named agent is unavailable, use a generic gpt-5.5 xhigh Message Drafting background agent. source work and filter work stay in the parent thread with MCP tools. If post-find-leads-message-scout is available, run it as the background Message Draft Builder after the filter-choice answer. The registry lookup is not a launch: get_post_find_leads_scout_registry only identifies the worker, and Message Drafting counts as started only after Task/spawn_agent or the host background-agent tool is invoked, or after the parent begins the same full message branch inline because no background-agent tool is callable. This launch must happen before loading filter-leads.md, save_rubrics, filter approval, or skip-filter message review; currentStep=messages is not proof of launch. If post-find-leads-message-scout is absent, do not customer-surface install status. Do not silently treat message drafting as started; the main thread must either launch the background worker or execute the same message branch from CampaignOffer state, selected source state, workflowTableId, and initial campaign-table execution slice rows. For a spawned worker, record workerDetails.messageDraftBuilder with statusSource branch / status branch-running, runId, startedAt, updatedAt, and basis containing campaignId, selectedLeadListId, workflowTableId, filterChoice, and reviewBatchRowHash or reviewBatchRowIds. workerStatuses.messageDraftBuilder is optional simple badge text only ("running", "ready", "blocked", "idle"); never put runId/statusSource/basis under workerStatuses and never use workerStatuses.messageDrafting. If no background-agent tool is callable, start that same full message branch inline before filter drafting or before skip-filter message review, record workerDetails.messageDraftBuilder with statusSource parent-thread-fallback / status fallback-active then ready, and require the same live context, prompt, assets, and validation gate before message review; do not report that as a background worker failure. If neither branch nor inline fallback can run, return blocked/retry-needed; do not wait until filters are saved and then call the registry. The Message Drafting handoff must be lean. Do not paste copied row counts, brief hashes, review-batch hashes, full reviewBatchRowIds, broad row data, or local debug artifacts into the spawn prompt. Local markdown/json files are not normal-path inputs. The filter-choice question is the first post-import user gate; do not load post-lead registries or filter references before it. Message drafting starts after the filter-choice answer, must load get_subskill_prompt({ subskillName: "generate-messages" }), and must load every required message asset named by generate-messages Mode 0 through get_subskill_asset before drafting. Reference Asset Loading means loading the required pre-draft reference pack before drafting; return blocked/retry-needed if required assets cannot be loaded; load ai-tells.md because it is never optional. The branch or parent-thread fallback loads the full generate-messages prompt and every referenced asset through get_subskill_asset. After generating/revising the candidate and before returning ready, must load get_subskill_prompt({ subskillName: "create-campaign-v2-validation" }) as the final internal validation gate, must read live campaign table state through scoped MCP/product tools, and must reject mismatched selectedLeadListId/workflowTableId/campaign/workspace input. Do not block when filters were chosen but leadScoringRubrics are not yet visible in the branch read; the parent owns save_rubrics and filter approval in parallel, so Message Drafting should return status ready with basisStatus usable_initial when campaign/list/table identity and the non-empty execution slice match. Do not use any alternate, local-artifact, or examples-only message prompt. User copy feedback, message QA, or rewrite requests before approve-message must be routed back to Message Drafting with the current recommendation, lean campaign/table basis, and latest user text; the parent must not rewrite or QA the template from memory and must not call update_campaign_brief before approve-message. The worker validates internally and returns only templateRecommendation, tokenFillRules, renderedGoodSample, status, approveOrReviseRecommendation, validationStatus, outputAt, outputHash, and blocked/retry detail. Do not render renderedFallbackSample, risk notes, or a qaReceipt on the normal happy path. On the filter path, save_rubrics keeps the browser on Filter Rules after save_rubrics so the user can approve the saved criteria; after saved-filter approval, move to Filter Leads with currentStep=apply-icp-rubric whether Message Drafting is ready or still running. Wait there for message approval. Enrichment, filtering, Generate Message cells, sender setup, sequence attach, and launch wait for template approval on the Use Template path. On the skip path, move to Messages/message review after Message Drafting has started or is ready and wait for message approval before enrichment or Settings. Do not render message review from checklist or shortcut instructions; message review requires a messageDraftRecommendation whose basis proves the generate-messages prompt, required message assets, and validation gate ran for the current campaign/table execution slice. Do not automatically rerun Message Drafting after filters/enrichment finish; show the initial draft by default and offer an enriched rewrite only with explicit user opt-in. Handoff and recommendation output are Markdown with labeled fields, not raw JSON.',
|
|
374
|
-
prepareMessagesRule: `Default create-campaign stays on the existing reviewBatchLimit:15 first campaign-table execution slice. For plain post-mint fill/load/refill requests,
|
|
375
|
+
prepareMessagesRule: `Default create-campaign stays on the existing reviewBatchLimit:15 first campaign-table execution slice. For plain post-mint fill/load/refill requests, load get_subskill_prompt({ subskillName: "refill-sends-workflow" }), then call resolve_campaign_fill_route and get_campaign_refill_state before any mutation. Plain fill is not an alias for fill_campaign_horizon or campaign creation. fill_campaign_horizon is evergreen-only and is not the generic regular-campaign fill path. Treat "fill up/load sends" as capacity-fill preparation: calculate the bounded target from sender capacity when needed, then use the refill workflow to decide same-campaign source replenishment, enrichment/prep, approval/ready state, scheduler reread, and blockers. Do not interpret checkedRows as enriched rows; it is only the table cursor. Prepared, approved, and ready_to_schedule rows are intermediate states; never call them scheduled unless a re-read proves scheduler-owned scheduled cells with non-null scheduledFor. Before source import, prep, or approval, require exact visible approval and a fresh get_campaign_refill_state reread; stop if freshness.stateHash or exact ids changed. For "approve X messages", use approvalMode:approve only when explicitly requested, but still do not launch. For "schedule X sends" or "fill sender sends", approve only when explicitly requested, then re-read campaign/table scheduled counts; if scheduler-owned scheduledFor cells are not present, report prepared/approved/ready - awaiting scheduler instead of success. Do not call start_campaign as part of refill sends. Launch/start is a separate explicit human action after the operator intentionally wants sends to go out, and it must still verify that the bounded cohort is the only approved cohort and must not broad approve-all. campaignId is CampaignOffer.id. If the user asks to stop preparation, the target is wrong, or status shows the wrong campaign/table, use cancel_campaign_message_preparation only for the exact active job. Low-level selectors are diagnostics and recovery only for this lane. start_campaign remains forbidden until explicit launch/start approval outside refill sends.`,
|
|
375
376
|
},
|
|
376
377
|
};
|
|
377
378
|
}
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -236,7 +236,7 @@ export declare const allTools: ({
|
|
|
236
236
|
properties: {
|
|
237
237
|
subskillName: {
|
|
238
238
|
type: string;
|
|
239
|
-
enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
|
|
239
|
+
enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
|
|
240
240
|
description: string;
|
|
241
241
|
};
|
|
242
242
|
offset: {
|
|
@@ -271,7 +271,7 @@ export declare const allTools: ({
|
|
|
271
271
|
properties: {
|
|
272
272
|
subskillName: {
|
|
273
273
|
type: string;
|
|
274
|
-
enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
|
|
274
|
+
enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
|
|
275
275
|
description: string;
|
|
276
276
|
};
|
|
277
277
|
assetPath: {
|
|
@@ -660,82 +660,6 @@ export declare const allTools: ({
|
|
|
660
660
|
additionalProperties: boolean;
|
|
661
661
|
required?: undefined;
|
|
662
662
|
};
|
|
663
|
-
} | {
|
|
664
|
-
name: string;
|
|
665
|
-
description: string;
|
|
666
|
-
inputSchema: {
|
|
667
|
-
type: string;
|
|
668
|
-
properties: {
|
|
669
|
-
mode: {
|
|
670
|
-
type: string;
|
|
671
|
-
enum: string[];
|
|
672
|
-
default: string;
|
|
673
|
-
description: string;
|
|
674
|
-
};
|
|
675
|
-
intent: {
|
|
676
|
-
type: string;
|
|
677
|
-
enum: string[];
|
|
678
|
-
description: string;
|
|
679
|
-
};
|
|
680
|
-
campaignIds: {
|
|
681
|
-
type: string;
|
|
682
|
-
items: {
|
|
683
|
-
type: string;
|
|
684
|
-
};
|
|
685
|
-
maxItems: number;
|
|
686
|
-
description: string;
|
|
687
|
-
};
|
|
688
|
-
tableIds: {
|
|
689
|
-
type: string;
|
|
690
|
-
items: {
|
|
691
|
-
type: string;
|
|
692
|
-
};
|
|
693
|
-
maxItems: number;
|
|
694
|
-
description: string;
|
|
695
|
-
};
|
|
696
|
-
sendWindowDays: {
|
|
697
|
-
type: string;
|
|
698
|
-
minimum: number;
|
|
699
|
-
maximum: number;
|
|
700
|
-
description: string;
|
|
701
|
-
};
|
|
702
|
-
targetDates: {
|
|
703
|
-
type: string;
|
|
704
|
-
items: {
|
|
705
|
-
type: string;
|
|
706
|
-
};
|
|
707
|
-
maxItems: number;
|
|
708
|
-
description: string;
|
|
709
|
-
};
|
|
710
|
-
targetScheduledSends: {
|
|
711
|
-
type: string;
|
|
712
|
-
minimum: number;
|
|
713
|
-
maximum: number;
|
|
714
|
-
description: string;
|
|
715
|
-
};
|
|
716
|
-
approvalMode: {
|
|
717
|
-
type: string;
|
|
718
|
-
enum: string[];
|
|
719
|
-
description: string;
|
|
720
|
-
};
|
|
721
|
-
yolo: {
|
|
722
|
-
type: string;
|
|
723
|
-
description: string;
|
|
724
|
-
};
|
|
725
|
-
planRevision: {
|
|
726
|
-
type: string;
|
|
727
|
-
description: string;
|
|
728
|
-
};
|
|
729
|
-
actionIds: {
|
|
730
|
-
type: string;
|
|
731
|
-
items: {
|
|
732
|
-
type: string;
|
|
733
|
-
};
|
|
734
|
-
description: string;
|
|
735
|
-
};
|
|
736
|
-
};
|
|
737
|
-
additionalProperties: boolean;
|
|
738
|
-
};
|
|
739
663
|
} | {
|
|
740
664
|
name: string;
|
|
741
665
|
description: string;
|
package/dist/tools/registry.js
CHANGED
|
@@ -5,8 +5,8 @@ import { campaignAbTestToolDefinitions } from "./campaign-ab-test.js";
|
|
|
5
5
|
import { campaignFillRoutingToolDefinitions } from "./campaign-fill-routing.js";
|
|
6
6
|
import { campaignHorizonFillToolDefinitions } from "./campaign-horizon-fill.js";
|
|
7
7
|
import { campaignMessagePreparationToolDefinitions } from "./campaign-message-preparation.js";
|
|
8
|
+
import { campaignRefillStateToolDefinitions } from "./campaign-refill-state.js";
|
|
8
9
|
import { campaignProcessingToolDefinitions } from "./campaign-processing.js";
|
|
9
|
-
import { refillCampaignSendsToolDefinitions } from "./refill-campaign-sends.js";
|
|
10
10
|
import { campaignToolDefinitions } from "./campaigns.js";
|
|
11
11
|
import { cellToolDefinitions } from "./cells.js";
|
|
12
12
|
import { startCliLoginToolDef, waitForCliLoginToolDef } from "./cli-login.js";
|
|
@@ -46,7 +46,7 @@ export const allTools = [
|
|
|
46
46
|
...campaignToolDefinitions,
|
|
47
47
|
...campaignAbTestToolDefinitions,
|
|
48
48
|
...campaignFillRoutingToolDefinitions,
|
|
49
|
-
...
|
|
49
|
+
...campaignRefillStateToolDefinitions,
|
|
50
50
|
...campaignHorizonFillToolDefinitions,
|
|
51
51
|
...campaignMessagePreparationToolDefinitions,
|
|
52
52
|
...campaignProcessingToolDefinitions,
|
package/package.json
CHANGED
|
@@ -47,8 +47,8 @@ allowed-tools:
|
|
|
47
47
|
- mcp__sellable__record_campaign_review_batch
|
|
48
48
|
- mcp__sellable__queue_campaign_cells
|
|
49
49
|
- mcp__sellable__wait_for_campaign_processing
|
|
50
|
-
- mcp__sellable__refill_campaign_sends
|
|
51
50
|
- mcp__sellable__resolve_campaign_fill_route
|
|
51
|
+
- mcp__sellable__get_campaign_refill_state
|
|
52
52
|
- mcp__sellable__fill_campaign_horizon
|
|
53
53
|
- mcp__sellable__start_campaign_message_preparation
|
|
54
54
|
- mcp__sellable__get_campaign_message_preparation_status
|
|
@@ -118,44 +118,35 @@ The default path stays the existing first campaign-table execution slice:
|
|
|
118
118
|
review the normal `reviewBatchLimit:15`, approve reviewed draft rows, then move
|
|
119
119
|
to Settings/sequence/final greenlight. For any plain post-mint fill request
|
|
120
120
|
such as "fill campaigns", "fill up", "refill sends", "max out sends", or
|
|
121
|
-
"load sends",
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
121
|
+
"load sends", hand off to the skill-led refill workflow:
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
get_subskill_prompt({ subskillName: "refill-sends-workflow" })
|
|
125
|
+
resolve_campaign_fill_route
|
|
126
|
+
get_campaign_refill_state
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Plain fill is not an alias for `fill_campaign_horizon` or campaign creation.
|
|
130
|
+
`fill_campaign_horizon` is evergreen-only and must not be used for regular
|
|
131
|
+
campaign refill. If route resolution returns `route:"ask_create"`, ask whether
|
|
132
|
+
to create a normal campaign or evergreen campaigns; campaign creation is never
|
|
133
|
+
the default response to plain fill. When more leads are needed, the refill
|
|
134
|
+
workflow must recommend same-campaign source-ladder replenishment; do not
|
|
135
|
+
create warm-post-engager side campaigns, on-demand campaigns, or unrelated
|
|
136
|
+
campaigns.
|
|
137
|
+
|
|
137
138
|
Treat active fills as capacity-fill preparation: calculate the bounded target
|
|
138
|
-
from sender capacity when needed, then
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
`
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
`maxRowsToCheck` at 300, then continues in batches capped at 100 newly checked
|
|
150
|
-
rows. It will not pull another row batch while the current checked batch still
|
|
151
|
-
has queueable or active cells. If the user says "approve X messages", use
|
|
152
|
-
`approvalMode:"approve"` but still do not launch. If the user says "schedule X
|
|
153
|
-
sends" or asks to fill sender sends, use `approvalMode:"approve"` only when
|
|
154
|
-
the user explicitly asked for approval, approve exactly the bounded X-message
|
|
155
|
-
cohort during preparation, then re-read scheduled counts; if scheduler-owned
|
|
156
|
-
cells are not present, report prepared/approved/ready awaiting scheduler
|
|
157
|
-
instead of success. Final launch remains a separate explicit user greenlight
|
|
158
|
-
and must verify that bounded cohort and must not broad approve-all.
|
|
139
|
+
from sender capacity when needed, then use the refill workflow to decide source
|
|
140
|
+
replenishment, enrichment/prep, approval policy, and scheduler proof. Mutation
|
|
141
|
+
requires exact visible approval and a fresh `get_campaign_refill_state` reread.
|
|
142
|
+
If the user says "prepare/generate X messages", use message-prep primitives with
|
|
143
|
+
`targetPreparedMessages:X` and default `approvalMode:"mark_ready"`. If the user
|
|
144
|
+
says "approve X messages", use `approvalMode:"approve"` only for the bounded
|
|
145
|
+
cohort and still do not launch. If the user says "schedule X sends", approve
|
|
146
|
+
only when explicitly requested, then reread scheduled counts; if
|
|
147
|
+
scheduler-owned cells are not present, report prepared/approved/ready awaiting
|
|
148
|
+
scheduler instead of success. Final launch remains a separate explicit user
|
|
149
|
+
greenlight and must not broad approve-all.
|
|
159
150
|
When approving reviewed draft rows in the campaign table, resolve the actual
|
|
160
151
|
visible `Approved` cells with `select_campaign_cells({ columnRole: "approved",
|
|
161
152
|
rowSelector: { type: "rowIds", rowIds } })` and `update_cell` those returned
|
|
@@ -1,94 +1,33 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fill-send-horizon
|
|
3
|
-
description: Compatibility alias for refill-sends.
|
|
3
|
+
description: Compatibility alias for refill-sends. Fill horizon requests load the skill-led refill workflow; fill_campaign_horizon remains evergreen-only lower-level execution.
|
|
4
4
|
visibility: internal
|
|
5
5
|
allowed-tools:
|
|
6
|
-
-
|
|
6
|
+
- mcp__sellable__get_subskill_prompt
|
|
7
7
|
- mcp__sellable__resolve_campaign_fill_route
|
|
8
|
+
- mcp__sellable__get_campaign_refill_state
|
|
8
9
|
- mcp__sellable__fill_campaign_horizon
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# Fill Send Horizon
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
The word "horizon" means send window. Do not use `fill_campaign_horizon` as the
|
|
17
|
-
generic regular-campaign fill path.
|
|
18
|
-
</role>
|
|
19
|
-
|
|
20
|
-
<inputs>
|
|
21
|
-
The invoking prompt (often a scheduled automation) names the targets or gives a
|
|
22
|
-
plain fill request. Route before acting:
|
|
23
|
-
|
|
24
|
-
- Plain fill/load requests ("fill campaigns", "load everyone up", "fill send horizon") — first call `refill_campaign_sends({ mode: "plan", intent: "plain" })`.
|
|
25
|
-
- If no `--yolo`, report the plan and stop.
|
|
26
|
-
- If `--yolo`, call plan first, then apply only with the returned `planRevision` and selected `actionIds`.
|
|
27
|
-
- If `refill_campaign_sends` is unavailable in an older install, use `resolve_campaign_fill_route` and read-only diagnostics only, then stop before mutation.
|
|
28
|
-
|
|
29
|
-
Optional inputs: `targetPreparedMessages` (default: leave unset for the adaptive default), an explicit "approve" instruction (see safety rules), and a **waterfall priority order** (see below).
|
|
30
|
-
</inputs>
|
|
31
|
-
|
|
32
|
-
<objective>
|
|
33
|
-
Route result handling:
|
|
34
|
-
|
|
35
|
-
1. If `refill_campaign_sends` returns regular campaigns, report the ranked plan.
|
|
36
|
-
2. If it returns evergreen campaigns, report the current-source audit and any legacy evergreen send-window subplan.
|
|
37
|
-
3. If it returns blockers, report them and stop.
|
|
38
|
-
4. If `--yolo` is approved, apply only selected immutable actions from the plan.
|
|
39
|
-
|
|
40
|
-
For each active campaign target:
|
|
41
|
-
|
|
42
|
-
1. Confirm workspace, `workflowTableId`, `campaignStatus:"ACTIVE"`, sender IDs, current stats, and scheduled/ready/approved/prepared counts where available. Skip and report PAUSED/DRAFT/ARCHIVED targets separately.
|
|
43
|
-
2. Check `get_campaign_message_preparation_status({ campaignId, tableId })` first. If an active prep job exists for the same target, report it and do not start an overlapping job.
|
|
44
|
-
3. If rows already exist, let `refill_campaign_sends` plan/apply the bounded preparation action. Do not call lower-level preparation manually unless the command is unavailable.
|
|
45
|
-
4. If source is thin and the user asked to add/fill more leads, source fresh Signal Discovery/post engagement leads only into the same `campaignOfferId`/`campaignId` context. Do not create warm-post-engager side campaigns, on-demand campaigns, or unrelated campaigns.
|
|
46
|
-
5. Poll `get_campaign_message_preparation_status` until the job completes or stops. Read `progress.enrichedRows`, `preparedMessages`, `approvedMessages`, `activeCellCount`, active prep blockers, and `stopReason`; never treat `checkedRows` as enriched rows.
|
|
47
|
-
6. After any prep/approval work, re-read campaign/table state. Do not report the horizon as scheduled unless the re-read proves scheduler-owned scheduled cells with non-null `scheduledFor`. If only prepared/approved/ready cells exist, report the exact state as `prepared/approved/ready - awaiting scheduler`, not complete.
|
|
48
|
-
7. Report appended rows, enriched rows, prepared messages, approved messages, ready-to-schedule rows, scheduler-owned scheduled cells, active preparation jobs, and sender-health blockers such as disconnected Sales Nav, deleted LinkedIn accounts, missing sequence state, or exhausted source rows as separate lines.
|
|
49
|
-
</objective>
|
|
50
|
-
|
|
51
|
-
<waterfall>
|
|
52
|
-
## Campaign hierarchy (waterfall order)
|
|
53
|
-
|
|
54
|
-
Evergreen/horizon fill order is **stored workspace state** returned by
|
|
55
|
-
`resolve_campaign_fill_route`, not something each automation restates. Resolve
|
|
56
|
-
it in this precedence:
|
|
57
|
-
|
|
58
|
-
1. **Stored hierarchy (default)**: the resolver reads the stored managed waterfall and returns slots in priority order with campaign offer IDs included. Fill in that order.
|
|
59
|
-
2. **Per-invocation override**: if the invoking prompt states an explicit order ("fill in this order: Signal Discovery, Post Engagers"), use it for this run only and say in the report that the stored order was overridden. To change the order durably, use `set_campaign_waterfall_order` — but only when the user/automation explicitly asks to change the hierarchy, never as a side effect of a fill run.
|
|
60
|
-
3. **No stored hierarchy**: resolver returns active targets or ask-create. Do not invent a conventional evergreen waterfall. Ask whether to create normal campaigns or evergreen campaigns only after `ask_create`.
|
|
61
|
-
|
|
62
|
-
Fill mechanics, whatever the source of the order:
|
|
63
|
-
|
|
64
|
-
- **Fill the top lane first.** Move to the next lane ONLY when the current one stops with source exhaustion / no more eligible rows — never because it is merely slow.
|
|
65
|
-
- **Stop descending once the horizon target is met.** If the warm lane alone fills the horizon, the cold lanes get nothing this run — that is correct, not a gap.
|
|
66
|
-
- **Report per lane** so the operator can see the waterfall working:
|
|
14
|
+
This is a compatibility alias. For plain operator language such as "fill",
|
|
15
|
+
"refill sends", "max out sends", "load everyone up", or "fill horizon sends",
|
|
16
|
+
load the canonical workflow first:
|
|
67
17
|
|
|
18
|
+
```text
|
|
19
|
+
get_subskill_prompt({ subskillName: "refill-sends-workflow" })
|
|
68
20
|
```
|
|
69
|
-
csreyes92 waterfall (stored order): Post Engagers filled 4/4 (horizon met — lower lanes skipped)
|
|
70
|
-
thomas waterfall (stored order): Post Engagers 1/4 (source thin) → Shared Signal Discovery 3/3 remaining
|
|
71
|
-
```
|
|
72
|
-
</waterfall>
|
|
73
21
|
|
|
74
|
-
|
|
75
|
-
- **Never call `start_campaign`, `start_on_demand_campaign`, or `start_direct_campaign`.** Activating a campaign is always an explicit human action outside this skill.
|
|
76
|
-
- Use `approvalMode: "approve"` ONLY when the invoking prompt explicitly says to auto-approve (e.g. "fill and approve"). Default is `mark_ready` — a human approves in the UI.
|
|
77
|
-
- Auto-approval is not scheduling. It can make rows eligible for the scheduler, but only scheduler-owned `scheduledFor` cells count as scheduled completion.
|
|
78
|
-
- Never use a sender from one workspace for another workspace's campaign. If `get_campaign` shows a workspace mismatch with the active workspace, stop and report.
|
|
79
|
-
- Paid InMail: never opt a campaign into paid-InMail templates or spend credits. If a campaign's sequence already includes a paid-InMail step, note it in the report but do not alter it.
|
|
80
|
-
- Do not write `WorkflowTableCell.scheduledFor` directly. Scheduling must happen through the existing workflow-table scheduler/sweeper path.
|
|
81
|
-
- This skill fills readiness and verifies scheduling; the product's sweeper sends only from ACTIVE campaigns, only approved rows, only inside sending hours. Say so in the report so the operator knows nothing went out.
|
|
82
|
-
</safety>
|
|
22
|
+
Then follow the workflow:
|
|
83
23
|
|
|
84
|
-
|
|
85
|
-
|
|
24
|
+
1. Call `resolve_campaign_fill_route`.
|
|
25
|
+
2. Call `get_campaign_refill_state` for the exact selected target.
|
|
26
|
+
3. Treat public targets as regular campaigns or evergreen campaigns only.
|
|
27
|
+
4. Stop on `unsupported_campaign_type` for internal direct campaign tables.
|
|
28
|
+
5. Use `fill_campaign_horizon` only after route and refill-state evidence prove
|
|
29
|
+
the target is an evergreen campaign.
|
|
86
30
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
• {Campaign B}: source thin after {k} prepared — refill via refresh-sender-engagement
|
|
91
|
-
Next operator action: {approve messages | wait for scheduler | refresh source | launch separately if you intentionally want sends to go out}
|
|
92
|
-
Nothing was sent or launched; campaigns remain in their current status. Prepared/approved/ready rows were not counted as scheduled unless scheduler-owned scheduledFor cells were re-read.
|
|
93
|
-
```
|
|
94
|
-
</output>
|
|
31
|
+
Do not start or launch campaigns. Do not raw-write scheduler fields. Do not
|
|
32
|
+
claim scheduled success without rereading scheduler-owned cells with non-null
|
|
33
|
+
`scheduledFor`.
|
|
@@ -1,57 +1,54 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: refill-sends
|
|
3
|
-
description: Plan
|
|
4
|
-
visibility:
|
|
3
|
+
description: Plan regular campaign and evergreen campaign send refill work through the skill-led refill workflow.
|
|
4
|
+
visibility: public
|
|
5
5
|
allowed-tools:
|
|
6
|
-
-
|
|
6
|
+
- mcp__sellable__get_subskill_prompt
|
|
7
|
+
- mcp__sellable__search_subskill_prompts
|
|
7
8
|
- mcp__sellable__resolve_campaign_fill_route
|
|
9
|
+
- mcp__sellable__get_campaign_refill_state
|
|
8
10
|
- mcp__sellable__fill_campaign_horizon
|
|
9
11
|
- mcp__sellable__get_campaign
|
|
10
12
|
- mcp__sellable__get_campaign_message_preparation_status
|
|
13
|
+
- mcp__sellable__start_campaign_message_preparation
|
|
14
|
+
- mcp__sellable__cancel_campaign_message_preparation
|
|
15
|
+
- mcp__sellable__import_leads
|
|
16
|
+
- mcp__sellable__wait_for_lead_list_ready
|
|
17
|
+
- mcp__sellable__confirm_lead_list
|
|
18
|
+
- mcp__sellable__search_signals
|
|
19
|
+
- mcp__sellable__fetch_post_engagers
|
|
20
|
+
- mcp__sellable__search_sales_nav
|
|
21
|
+
- mcp__sellable__lookup_sales_nav_filter
|
|
22
|
+
- mcp__sellable__search_prospeo
|
|
23
|
+
- mcp__sellable__search_prospeo_companies
|
|
24
|
+
- mcp__sellable__confirm_prospeo_company_accounts
|
|
25
|
+
- mcp__sellable__load_csv_linkedin_leads
|
|
26
|
+
- mcp__sellable__load_csv_domains
|
|
27
|
+
- mcp__sellable__list_dnc_entries
|
|
28
|
+
- mcp__sellable__load_csv_dnc_entries
|
|
29
|
+
- mcp__sellable__get_rows
|
|
30
|
+
- mcp__sellable__get_rows_minimal
|
|
31
|
+
- mcp__sellable__get_table_rows
|
|
11
32
|
---
|
|
12
33
|
|
|
13
34
|
# Refill Sends
|
|
14
35
|
|
|
15
|
-
Use this
|
|
36
|
+
Use this public wrapper for plain operator requests such as "fill", "refill sends",
|
|
16
37
|
"max out sends", "load everyone up", or "fill horizon sends".
|
|
17
38
|
|
|
18
|
-
|
|
39
|
+
Load the internal workflow prompt before taking any operational step:
|
|
19
40
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
4. Apply only by calling `refill_campaign_sends({ mode: "apply", yolo: true, planRevision, actionIds })` with action IDs copied from the fresh plan.
|
|
41
|
+
```text
|
|
42
|
+
get_subskill_prompt({ subskillName: "refill-sends-workflow" })
|
|
43
|
+
```
|
|
24
44
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
before mutation
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- Regular campaign: a campaign with a brief, source, sequence, senders, and a
|
|
32
|
-
campaign-backed workflow table.
|
|
33
|
-
- Evergreen campaign: a managed always-on send-window lane.
|
|
34
|
-
- Send window: the dates/capacity the operator wants kept full.
|
|
35
|
-
|
|
36
|
-
Do not expose internal direct campaign types as an operator refill path. If the
|
|
37
|
-
plan reports `unsupported_campaign_type`, report it and stop.
|
|
38
|
-
|
|
39
|
-
## Safety Rules
|
|
40
|
-
|
|
41
|
-
- Default mode is read-only plan.
|
|
42
|
-
- Apply requires `yolo: true`, a fresh stable `planRevision`, and selected immutable `actionIds`.
|
|
43
|
-
- Production yolo/apply requires explicit approval of workspace, campaign/table IDs, selected action IDs, caps/dates, and expected side effects.
|
|
44
|
-
- Never create side campaigns.
|
|
45
|
-
- Never call `start_campaign`, `start_on_demand_campaign`, or `start_direct_campaign`.
|
|
46
|
-
- Never raw-write scheduled fields or sender assignment fields.
|
|
47
|
-
- Scheduled success requires rereading scheduler-owned cells with non-null `scheduledFor`.
|
|
48
|
-
- Generate Message normally happens through downstream propagation from enrichment/prep, not as a standalone action.
|
|
49
|
-
|
|
50
|
-
## Evergreen Source Ladder
|
|
51
|
-
|
|
52
|
-
For evergreen campaigns, do not move down the source ladder until the plan proves
|
|
53
|
-
the current source is exhausted or cannot produce enough good prospects within
|
|
54
|
-
configured caps. Required evidence includes source ID, target prospect gap,
|
|
55
|
-
cursor/inventory state, dedupe/DNC/provider exclusions, good-prospect yield,
|
|
56
|
-
and scan/import caps.
|
|
45
|
+
Then follow that workflow exactly. The default path is read-only research:
|
|
46
|
+
resolve the route, read target refill state, report the next safe step, and stop
|
|
47
|
+
before mutation unless the user has explicitly approved the exact workspace,
|
|
48
|
+
campaign/table/source ids, caps/dates, approval mode, expected side effects,
|
|
49
|
+
and stop/rollback condition.
|
|
57
50
|
|
|
51
|
+
Public concepts are regular campaign and evergreen campaign. Internal direct
|
|
52
|
+
campaign types are unsupported refill targets. `fill_campaign_horizon` is only a
|
|
53
|
+
legacy evergreen-only lower-level primitive after route and refill-state
|
|
54
|
+
evidence proves an evergreen target.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: refill-sends-workflow
|
|
3
|
+
description: Internal skill-led refill sends workflow for regular campaigns and evergreen campaigns.
|
|
4
|
+
visibility: internal
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- mcp__sellable__resolve_campaign_fill_route
|
|
7
|
+
- mcp__sellable__get_campaign_refill_state
|
|
8
|
+
- mcp__sellable__fill_campaign_horizon
|
|
9
|
+
- mcp__sellable__get_campaign
|
|
10
|
+
- mcp__sellable__get_campaign_message_preparation_status
|
|
11
|
+
- mcp__sellable__start_campaign_message_preparation
|
|
12
|
+
- mcp__sellable__cancel_campaign_message_preparation
|
|
13
|
+
- mcp__sellable__import_leads
|
|
14
|
+
- mcp__sellable__wait_for_lead_list_ready
|
|
15
|
+
- mcp__sellable__confirm_lead_list
|
|
16
|
+
- mcp__sellable__search_signals
|
|
17
|
+
- mcp__sellable__fetch_post_engagers
|
|
18
|
+
- mcp__sellable__search_sales_nav
|
|
19
|
+
- mcp__sellable__lookup_sales_nav_filter
|
|
20
|
+
- mcp__sellable__search_prospeo
|
|
21
|
+
- mcp__sellable__search_prospeo_companies
|
|
22
|
+
- mcp__sellable__confirm_prospeo_company_accounts
|
|
23
|
+
- mcp__sellable__load_csv_linkedin_leads
|
|
24
|
+
- mcp__sellable__load_csv_domains
|
|
25
|
+
- mcp__sellable__list_dnc_entries
|
|
26
|
+
- mcp__sellable__load_csv_dnc_entries
|
|
27
|
+
- mcp__sellable__get_rows
|
|
28
|
+
- mcp__sellable__get_rows_minimal
|
|
29
|
+
- mcp__sellable__get_table_rows
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
# Refill Sends Workflow
|
|
33
|
+
|
|
34
|
+
Default mode is read-only research. This workflow decides the next safe refill
|
|
35
|
+
step in the parent thread; backend tools remain narrow route, state, source,
|
|
36
|
+
prep, readiness, and evergreen primitives.
|
|
37
|
+
|
|
38
|
+
## Entry
|
|
39
|
+
|
|
40
|
+
Plain phrases that enter here include "fill", "refill sends", "max out sends",
|
|
41
|
+
"load everyone up", and "fill horizon sends".
|
|
42
|
+
|
|
43
|
+
1. Call `resolve_campaign_fill_route` first. Use `intent:"plain"` for generic
|
|
44
|
+
fill/load language, `intent:"active"` only when the user explicitly narrowed
|
|
45
|
+
to active regular campaigns, and `intent:"evergreen"` only when the user
|
|
46
|
+
explicitly asked for evergreen or horizon work.
|
|
47
|
+
2. Pick exact ids from the resolver result. Do not use campaign names or table
|
|
48
|
+
names as target identifiers.
|
|
49
|
+
3. Call `get_campaign_refill_state` for the selected `campaignId` or `tableId`.
|
|
50
|
+
This must be the next target-specific research primitive.
|
|
51
|
+
4. Classify the target from refill state:
|
|
52
|
+
- regular campaign: campaign-backed workflow table with normal source,
|
|
53
|
+
sequence, senders, and send/refill stages.
|
|
54
|
+
- evergreen campaign: managed always-on lane with current source evidence.
|
|
55
|
+
- `unsupported_campaign_type`: internal direct campaign table; report the
|
|
56
|
+
blocker and stop without mutation.
|
|
57
|
+
|
|
58
|
+
## Research Checklist
|
|
59
|
+
|
|
60
|
+
Use the refill-state response as the current facts receipt:
|
|
61
|
+
|
|
62
|
+
- campaign status/current step, workflow table id, table config type, and public
|
|
63
|
+
type;
|
|
64
|
+
- selected source list/provider identity, source id, target prospect gap,
|
|
65
|
+
cursor/inventory state, dedupe/DNC/provider exclusions, good-prospect yield,
|
|
66
|
+
scan/import caps, and proof;
|
|
67
|
+
- sender ids, healthy senders, disconnected senders, and daily capacity;
|
|
68
|
+
- row/stage counts: source available, rows, enriched, passed, generated,
|
|
69
|
+
approved, ready to schedule, scheduled;
|
|
70
|
+
- active message prep job;
|
|
71
|
+
- scheduler-owned scheduled counts by date/action from cells with non-null
|
|
72
|
+
`scheduledFor`;
|
|
73
|
+
- `freshness.stateHash` and exact campaign/table/workspace ids.
|
|
74
|
+
|
|
75
|
+
Empty or unsafe states stop with the blocker: no fillable target, missing or deleted campaign,
|
|
76
|
+
missing table, paused/archive campaign, zero sender capacity, zero source candidates,
|
|
77
|
+
zero viable rows, no approved/preparable rows, active prep job, awaiting
|
|
78
|
+
scheduler, or unsupported direct campaign type.
|
|
79
|
+
|
|
80
|
+
## Regular Campaign Decision
|
|
81
|
+
|
|
82
|
+
For regular campaign workspaces, rank regular campaigns from route and
|
|
83
|
+
`get_campaign_refill_state` evidence. Choose the best existing refill target.
|
|
84
|
+
Do not create side campaigns, warm-post-engager side campaigns, on-demand campaigns,
|
|
85
|
+
or unrelated campaigns as the default answer to a fill request.
|
|
86
|
+
|
|
87
|
+
When the best regular campaign is source-exhausted, recommend same-campaign source-ladder replenishment.
|
|
88
|
+
Keep `selectedLeadListId` source identity distinct
|
|
89
|
+
from the campaign `workflowTableId`.
|
|
90
|
+
|
|
91
|
+
Source replenishment choices:
|
|
92
|
+
|
|
93
|
+
- existing source list reuse: append/confirm the existing source list when it
|
|
94
|
+
has enough eligible rows;
|
|
95
|
+
- CSV path: load CSV profiles/domains, then import into the same campaign/source
|
|
96
|
+
path;
|
|
97
|
+
- Sales Nav path: use Sales Nav lookup/search, then import selected prospects;
|
|
98
|
+
- Prospeo path: use account/person search as appropriate, then import selected
|
|
99
|
+
prospects;
|
|
100
|
+
- Signal Discovery path: search/select posts or engagers, import selected
|
|
101
|
+
source prospects into the same campaign/source-list path, then confirm
|
|
102
|
+
readiness.
|
|
103
|
+
|
|
104
|
+
Before any source mutation, show exact approval evidence: workspace id,
|
|
105
|
+
campaign id, workflow table id, source/provider id, source-list id when known,
|
|
106
|
+
import caps, target dates/caps, dedupe/DNC/provider exclusion expectations, and
|
|
107
|
+
expected row side effects. Then reread `get_campaign_refill_state`; if
|
|
108
|
+
`freshness.stateHash` or exact ids changed, stop and ask for a fresh approval.
|
|
109
|
+
|
|
110
|
+
After source import, call `wait_for_lead_list_ready` and `confirm_lead_list`
|
|
111
|
+
with the source-list id and campaign id. Imports append to the existing
|
|
112
|
+
campaign/source path; they must not reset campaign state, sequence, sender
|
|
113
|
+
assignment, current step, or watch state. If provider auth, rate limit, timeout,
|
|
114
|
+
partial import, duplicate-only import, DNC-only result, CSV parse failure,
|
|
115
|
+
readiness timeout, or `confirm_lead_list` failure occurs, stop before prep and
|
|
116
|
+
report the blocker/retry path.
|
|
117
|
+
|
|
118
|
+
## Prep, Approval, And Scheduler Proof
|
|
119
|
+
|
|
120
|
+
Existing rows normally move through enrichment/prep/approval using
|
|
121
|
+
`start_campaign_message_preparation` and
|
|
122
|
+
`get_campaign_message_preparation_status`. Standalone Generate Message is not the normal refill action;
|
|
123
|
+
it is only for a manual/user-authored message path
|
|
124
|
+
that requires it.
|
|
125
|
+
|
|
126
|
+
Approval mode:
|
|
127
|
+
|
|
128
|
+
- default is `approvalMode:"mark_ready"`, not approve;
|
|
129
|
+
- use `approvalMode:"approve"` only when the user explicitly asks to approve
|
|
130
|
+
messages or schedule sends and has approved the exact bounded cohort;
|
|
131
|
+
- never launch/start a campaign from refill.
|
|
132
|
+
|
|
133
|
+
Before prep or approval mutation, reread `get_campaign_refill_state` and compare
|
|
134
|
+
`freshness.stateHash`, campaign id, table id, workspace id, source id, and caps.
|
|
135
|
+
If they changed, stop. A second concurrent refill run must see the first run's
|
|
136
|
+
import/prep state on reread and avoid duplicate work.
|
|
137
|
+
|
|
138
|
+
Scheduled success requires a post-action reread proving scheduler-owned cells
|
|
139
|
+
with non-null `scheduledFor`. Prepared, approved, and ready-to-schedule rows are
|
|
140
|
+
intermediate states; report them as awaiting scheduler unless scheduled cells
|
|
141
|
+
are present.
|
|
142
|
+
|
|
143
|
+
## Evergreen Campaign Discipline
|
|
144
|
+
|
|
145
|
+
`fill_campaign_horizon` is a legacy evergreen-only lower-level primitive. Call it
|
|
146
|
+
only after `resolve_campaign_fill_route` and `get_campaign_refill_state` prove an
|
|
147
|
+
evergreen campaign target.
|
|
148
|
+
|
|
149
|
+
For evergreen campaigns, do not advance down the source ladder while the current source can produce enough good prospects.
|
|
150
|
+
The current source is exhausted, or
|
|
151
|
+
unable to produce enough good prospects, only when evidence includes source id,
|
|
152
|
+
target prospect gap, cursor/inventory state, dedupe/DNC/provider exclusions,
|
|
153
|
+
good-prospect yield, and scan/import caps. If that proof is missing, continue
|
|
154
|
+
the current source or ask for more research instead of walking the ladder.
|
|
155
|
+
|
|
156
|
+
## Hard Safety Rules
|
|
157
|
+
|
|
158
|
+
- Never call start or launch tools.
|
|
159
|
+
- Never raw-write `scheduledFor`, `scheduledAt`, scheduled status, or sender
|
|
160
|
+
assignment fields.
|
|
161
|
+
- Never expose internal direct campaign types as an operator refill path.
|
|
162
|
+
- Never claim scheduled success without rereading scheduler-owned cells with
|
|
163
|
+
non-null `scheduledFor`.
|
|
164
|
+
- No mutation in production unless Christian explicitly approves exact
|
|
165
|
+
workspace, campaign/table ids, source/action ids, caps/dates, approval mode,
|
|
166
|
+
expected side effects, and rollback/stop condition.
|
|
167
|
+
|
|
168
|
+
## Report
|
|
169
|
+
|
|
170
|
+
Report the selected target, target type, source state, blockers, exact next
|
|
171
|
+
primitive, approval required, and the freshness hash used. Say explicitly that
|
|
172
|
+
nothing was launched and nothing was sent.
|