@sellable/mcp 0.1.190 → 0.1.191

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 CHANGED
@@ -435,7 +435,7 @@ Sellable writing workflows.
435
435
 
436
436
  ### "Sellable not configured" Error
437
437
 
438
- Create `~/.sellable/config.json` with your token. Get one at https://app.sellable.dev/settings/integrations.
438
+ Create `~/.sellable/config.json` with your token. Get one at https://app.sellable.dev/settings?tab=integrations.
439
439
 
440
440
  ### Token Not Working
441
441
 
@@ -37,14 +37,13 @@ the branch input.
37
37
 
38
38
  ## Required First Steps
39
39
 
40
- 1. Load the compact normal-path message prompt:
40
+ 1. Load the full long-form generate-messages prompt:
41
41
 
42
- `get_subskill_prompt({ subskillName: "generate-messages-compact" })`
42
+ `get_subskill_prompt({ subskillName: "generate-messages", offset, limit })`
43
+ until `hasMore` is false.
43
44
 
44
- 2. Use that prompt as the drafting contract. Load
45
- `generate-messages-compact/references/examples-critique-revision.md` only for
46
- critique, revision, or close-call examples. Do not use create-campaign
47
- safety/checklist instructions as a substitute for the message prompt.
45
+ 2. Use that prompt as the drafting contract. Do not use create-campaign
46
+ safety/checklist instructions as a substitute for the full prompt.
48
47
  3. Draft only from the campaign brief, selected source context, and initial
49
48
  campaign-table execution slice rows supplied by the parent.
50
49
  4. Keep the work provisional until the user chooses `Use Template` in Messages.
@@ -57,7 +56,7 @@ Return the following to the parent thread:
57
56
  - token fill rules and fallbacks
58
57
  - one rendered good-fill sample for a plausible passing campaign-table row
59
58
  - one omit/fallback sample when the row signal is not safe
60
- - pass/fail notes against the generate-messages-compact quality gates
59
+ - pass/fail notes against the generate-messages quality gates
61
60
  - compact runtime status: `ready`, `blocked`, `retry-needed`, or `stale`
62
61
  - basis token containing campaign revision/updatedAt, brief hash,
63
62
  `selectedLeadListId`, `workflowTableId`, execution-slice row ids/hash, filter
@@ -137,7 +136,7 @@ enablement`, or omit it.
137
136
 
138
137
  Return a concise status with:
139
138
 
140
- - prompt basis loaded: `generate-messages-compact`
139
+ - prompt basis loaded: `generate-messages`
141
140
  - live campaign basis used
142
141
  - proposed template
143
142
  - token fill rules/fallbacks
@@ -197,7 +197,7 @@
197
197
  "kind": "post-find-leads-scout",
198
198
  "promptFile": "post-find-leads-message-scout.md",
199
199
  "displayName": "Message Draft Builder",
200
- "target": "generate-messages-compact",
200
+ "target": "generate-messages",
201
201
  "inputs": [
202
202
  "campaignId",
203
203
  "campaignBrief",
@@ -225,7 +225,7 @@
225
225
  ]
226
226
  },
227
227
  "claude": {
228
- "description": "Use proactively as Message Draft Builder after confirm_lead_list imports a non-empty bounded review batch; load generate-messages-compact and draft only from scoped campaign/tool state.",
228
+ "description": "Use proactively as Message Draft Builder after confirm_lead_list imports a non-empty bounded review batch; load the full generate-messages prompt and draft only from scoped campaign/tool state.",
229
229
  "model": "inherit",
230
230
  "background": true,
231
231
  "maxTurns": 10,
package/dist/auth.js CHANGED
@@ -72,7 +72,7 @@ export function getConfig() {
72
72
  "}\n\n" +
73
73
  "Config path resolution order:\n" +
74
74
  `${renderConfigPathOrder(configPathCandidates)}\n\n` +
75
- "Get your token at: https://app.sellable.dev/settings/integrations\n" +
75
+ "Get your token at: https://app.sellable.dev/settings?tab=integrations\n" +
76
76
  "Then run list_workspaces + set_active_workspace to select a workspace.");
77
77
  }
78
78
  try {
package/dist/index-dev.js CHANGED
File without changes
package/dist/index.js CHANGED
File without changes
package/dist/server.js CHANGED
@@ -6,7 +6,6 @@ import { getAuthStatus } from "./tools/auth.js";
6
6
  import { handleAddColumn, handleCommitBlueprint, } from "./tools/blueprint-commit.js";
7
7
  import { bootstrapCreateCampaign } from "./tools/bootstrap.js";
8
8
  import { createCampaign, getCampaign, getCampaignMessagesPreview, getCampaigns, pauseCampaign, startCampaign, updateCampaign, updateCampaignBrief, } from "./tools/campaigns.js";
9
- import { getCampaignTableSchema, queueCampaignCells, reviseMessageTemplateAndRerun, selectCampaignCells, waitForCampaignProcessing, } from "./tools/campaign-processing.js";
10
9
  import { queueCells, updateCell } from "./tools/cells.js";
11
10
  import { handleStartCliLogin, handleWaitForCliLogin, } from "./tools/cli-login.js";
12
11
  import { getCampaignContext, hydrateCampaignContextFromCampaign, markCampaignContextDirty, } from "./tools/context.js";
@@ -161,27 +160,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
161
160
  case "get_campaign_messages_preview":
162
161
  result = await getCampaignMessagesPreview(args);
163
162
  break;
164
- case "get_campaign_table_schema":
165
- result = await getCampaignTableSchema(args);
166
- break;
167
- case "select_campaign_cells":
168
- result = await selectCampaignCells(args);
169
- break;
170
- case "queue_campaign_cells":
171
- result = await queueCampaignCells(args);
172
- if (args?.campaignId) {
173
- markCampaignContextDirty(args.campaignId, "queue_campaign_cells");
174
- }
175
- break;
176
- case "wait_for_campaign_processing":
177
- result = await waitForCampaignProcessing(args);
178
- break;
179
- case "revise_message_template_and_rerun":
180
- result = await reviseMessageTemplateAndRerun(args);
181
- if (args?.campaignId) {
182
- markCampaignContextDirty(args.campaignId, "revise_message_template_and_rerun");
183
- }
184
- break;
185
163
  case "create_campaign":
186
164
  result = await createCampaign(args);
187
165
  if (result?.id)
@@ -146,7 +146,6 @@ export type ConfirmLeadListInput = {
146
146
  keepInSync?: boolean;
147
147
  jobId?: string;
148
148
  reviewBatchLimit?: number;
149
- includeRawImportResult?: boolean;
150
149
  allowPartialSourceList?: boolean;
151
150
  /**
152
151
  * Deprecated alias for reviewBatchLimit. Confirming a lead list now copies the
@@ -247,7 +246,6 @@ export declare const leadToolDefinitions: ({
247
246
  jobId?: undefined;
248
247
  reviewBatchLimit?: undefined;
249
248
  allowPartialSourceList?: undefined;
250
- includeRawImportResult?: undefined;
251
249
  selections?: undefined;
252
250
  selectionMode?: undefined;
253
251
  };
@@ -425,7 +423,6 @@ export declare const leadToolDefinitions: ({
425
423
  jobId?: undefined;
426
424
  reviewBatchLimit?: undefined;
427
425
  allowPartialSourceList?: undefined;
428
- includeRawImportResult?: undefined;
429
426
  selections?: undefined;
430
427
  selectionMode?: undefined;
431
428
  };
@@ -502,7 +499,6 @@ export declare const leadToolDefinitions: ({
502
499
  jobId?: undefined;
503
500
  reviewBatchLimit?: undefined;
504
501
  allowPartialSourceList?: undefined;
505
- includeRawImportResult?: undefined;
506
502
  selections?: undefined;
507
503
  selectionMode?: undefined;
508
504
  };
@@ -651,7 +647,6 @@ export declare const leadToolDefinitions: ({
651
647
  jobId?: undefined;
652
648
  reviewBatchLimit?: undefined;
653
649
  allowPartialSourceList?: undefined;
654
- includeRawImportResult?: undefined;
655
650
  selections?: undefined;
656
651
  selectionMode?: undefined;
657
652
  };
@@ -742,7 +737,6 @@ export declare const leadToolDefinitions: ({
742
737
  jobId?: undefined;
743
738
  reviewBatchLimit?: undefined;
744
739
  allowPartialSourceList?: undefined;
745
- includeRawImportResult?: undefined;
746
740
  selections?: undefined;
747
741
  selectionMode?: undefined;
748
742
  };
@@ -842,7 +836,6 @@ export declare const leadToolDefinitions: ({
842
836
  jobId?: undefined;
843
837
  reviewBatchLimit?: undefined;
844
838
  allowPartialSourceList?: undefined;
845
- includeRawImportResult?: undefined;
846
839
  selections?: undefined;
847
840
  selectionMode?: undefined;
848
841
  };
@@ -924,7 +917,6 @@ export declare const leadToolDefinitions: ({
924
917
  jobId?: undefined;
925
918
  reviewBatchLimit?: undefined;
926
919
  allowPartialSourceList?: undefined;
927
- includeRawImportResult?: undefined;
928
920
  selections?: undefined;
929
921
  selectionMode?: undefined;
930
922
  };
@@ -1545,7 +1537,6 @@ export declare const leadToolDefinitions: ({
1545
1537
  jobId?: undefined;
1546
1538
  reviewBatchLimit?: undefined;
1547
1539
  allowPartialSourceList?: undefined;
1548
- includeRawImportResult?: undefined;
1549
1540
  selections?: undefined;
1550
1541
  selectionMode?: undefined;
1551
1542
  };
@@ -1679,7 +1670,6 @@ export declare const leadToolDefinitions: ({
1679
1670
  jobId?: undefined;
1680
1671
  reviewBatchLimit?: undefined;
1681
1672
  allowPartialSourceList?: undefined;
1682
- includeRawImportResult?: undefined;
1683
1673
  selections?: undefined;
1684
1674
  selectionMode?: undefined;
1685
1675
  };
@@ -1801,7 +1791,6 @@ export declare const leadToolDefinitions: ({
1801
1791
  jobId?: undefined;
1802
1792
  reviewBatchLimit?: undefined;
1803
1793
  allowPartialSourceList?: undefined;
1804
- includeRawImportResult?: undefined;
1805
1794
  selections?: undefined;
1806
1795
  selectionMode?: undefined;
1807
1796
  };
@@ -1881,7 +1870,6 @@ export declare const leadToolDefinitions: ({
1881
1870
  jobId?: undefined;
1882
1871
  reviewBatchLimit?: undefined;
1883
1872
  allowPartialSourceList?: undefined;
1884
- includeRawImportResult?: undefined;
1885
1873
  selections?: undefined;
1886
1874
  selectionMode?: undefined;
1887
1875
  };
@@ -1933,10 +1921,6 @@ export declare const leadToolDefinitions: ({
1933
1921
  type: string;
1934
1922
  description: string;
1935
1923
  };
1936
- includeRawImportResult: {
1937
- type: string;
1938
- description: string;
1939
- };
1940
1924
  provider?: undefined;
1941
1925
  searchMode?: undefined;
1942
1926
  organization_num_employees_ranges?: undefined;
@@ -2099,7 +2083,6 @@ export declare const leadToolDefinitions: ({
2099
2083
  jobId?: undefined;
2100
2084
  reviewBatchLimit?: undefined;
2101
2085
  allowPartialSourceList?: undefined;
2102
- includeRawImportResult?: undefined;
2103
2086
  };
2104
2087
  required: string[];
2105
2088
  };
@@ -2181,7 +2164,6 @@ export declare const leadToolDefinitions: ({
2181
2164
  jobId?: undefined;
2182
2165
  reviewBatchLimit?: undefined;
2183
2166
  allowPartialSourceList?: undefined;
2184
- includeRawImportResult?: undefined;
2185
2167
  selections?: undefined;
2186
2168
  selectionMode?: undefined;
2187
2169
  };
@@ -2626,13 +2608,25 @@ export declare function cancelLeadImport(input: CancelLeadImportInput): Promise<
2626
2608
  previousStatus?: undefined;
2627
2609
  }>;
2628
2610
  export declare function confirmLeadList(input: ConfirmLeadListInput): Promise<{
2629
- reviewBatch: {
2630
- tableId: string | null;
2631
- rowCount: number;
2632
- rowIds: string[];
2633
- enrichCellIds: string[];
2634
- basisHash: string | null;
2635
- recordedAt: string | null;
2611
+ sourceLeadListId: string;
2612
+ campaignTableId: string | null;
2613
+ importResult: {
2614
+ workflowTableId?: string;
2615
+ campaignTableId?: string;
2616
+ campaignTableName?: string;
2617
+ leadsImported?: number;
2618
+ leadsSkipped?: number;
2619
+ rowIds?: string[];
2620
+ requestedTargetLeadCount?: number;
2621
+ sourceRowLimit?: number;
2622
+ async?: boolean;
2623
+ hybrid?: boolean;
2624
+ campaignTableReady?: boolean;
2625
+ importStatus?: string | null;
2626
+ remainingRowCount?: number | null;
2627
+ rowCount?: number | null;
2628
+ sourceRowCount?: number | null;
2629
+ clonedSourceRowCount?: number | null;
2636
2630
  };
2637
2631
  messageDraftBuilder: {
2638
2632
  firstAllowedStartPoint: string;
@@ -2643,7 +2637,6 @@ export declare function confirmLeadList(input: ConfirmLeadListInput): Promise<{
2643
2637
  selectedLeadListId: string;
2644
2638
  workflowTableId: string | null;
2645
2639
  reviewBatchRowIds: string[];
2646
- reviewBatchBasisHash: string | null;
2647
2640
  reviewBatchRowCount: number;
2648
2641
  copiedCampaignRowCount: number;
2649
2642
  };
@@ -2672,43 +2665,6 @@ export declare function confirmLeadList(input: ConfirmLeadListInput): Promise<{
2672
2665
  warning: string | null;
2673
2666
  };
2674
2667
  message: string;
2675
- importResult?: {
2676
- workflowTableId?: string;
2677
- campaignTableId?: string;
2678
- campaignTableName?: string;
2679
- leadsImported?: number;
2680
- leadsSkipped?: number;
2681
- rowIds?: string[];
2682
- requestedTargetLeadCount?: number;
2683
- sourceRowLimit?: number;
2684
- async?: boolean;
2685
- hybrid?: boolean;
2686
- campaignTableReady?: boolean;
2687
- importStatus?: string | null;
2688
- remainingRowCount?: number | null;
2689
- rowCount?: number | null;
2690
- sourceRowCount?: number | null;
2691
- clonedSourceRowCount?: number | null;
2692
- } | undefined;
2693
- sourceLeadListId: string;
2694
- campaignTableId: string | null;
2695
- importSummary: {
2696
- workflowTableId: string | null;
2697
- campaignTableId: string | null;
2698
- campaignTableName: string | null;
2699
- leadsImported: number | null;
2700
- leadsSkipped: number | null;
2701
- rowCount: number;
2702
- requestedTargetLeadCount: number | null;
2703
- sourceRowLimit: number | null;
2704
- async: boolean;
2705
- hybrid: boolean;
2706
- campaignTableReady: true;
2707
- importStatus: string | null;
2708
- remainingRowCount: number;
2709
- sourceRowCount: number | null;
2710
- clonedSourceRowCount: number | null;
2711
- };
2712
2668
  }>;
2713
2669
  export declare function getProviderPrompt(input: GetProviderPromptInput): string;
2714
2670
  export declare function selectPromisingPosts(input: SelectPromisingPostsInput): Promise<{
@@ -1518,10 +1518,6 @@ export const leadToolDefinitions = [
1518
1518
  type: "boolean",
1519
1519
  description: "Set true after user approval when interaction mode requires confirmation for confirm/import.",
1520
1520
  },
1521
- includeRawImportResult: {
1522
- type: "boolean",
1523
- description: "Debug only. When true, include the raw import response; default compact output omits large row-id payloads.",
1524
- },
1525
1521
  },
1526
1522
  required: ["campaignOfferId"],
1527
1523
  },
@@ -2745,7 +2741,7 @@ export async function cancelLeadImport(input) {
2745
2741
  }
2746
2742
  export async function confirmLeadList(input) {
2747
2743
  const api = getApi();
2748
- const { campaignOfferId, currentStep, confirmed, sourceLeadListId, campaignName, keepInSync, jobId, reviewBatchLimit, includeRawImportResult, allowPartialSourceList, targetLeadCount, } = input;
2744
+ const { campaignOfferId, currentStep, confirmed, sourceLeadListId, campaignName, keepInSync, jobId, reviewBatchLimit, allowPartialSourceList, targetLeadCount, } = input;
2749
2745
  assertInteractionApproval({
2750
2746
  campaignId: campaignOfferId,
2751
2747
  action: "confirm-lead-list",
@@ -2992,50 +2988,6 @@ export async function confirmLeadList(input) {
2992
2988
  reviewSampleRows = [];
2993
2989
  }
2994
2990
  }
2995
- const sampleReviewRowIds = reviewSampleRows
2996
- .map((row) => row.id)
2997
- .filter((rowId) => typeof rowId === "string");
2998
- const reviewBatchRowIds = importedRowIds.length > 0
2999
- ? importedRowIds.slice(0, keptReviewRowCount)
3000
- : sampleReviewRowIds.slice(0, keptReviewRowCount);
3001
- const reviewBatchEnrichCellIds = reviewSampleRows
3002
- .map((row) => row.enrichCellId)
3003
- .filter((cellId) => typeof cellId === "string");
3004
- let recordedReviewBatch = null;
3005
- if (campaignTableId && reviewBatchRowIds.length > 0) {
3006
- const recordResult = await api.post("/api/v3/mcp/campaign-processing", {
3007
- action: "recordReviewBatch",
3008
- tableId: campaignTableId,
3009
- rowIds: reviewBatchRowIds,
3010
- enrichCellIds: reviewBatchEnrichCellIds,
3011
- });
3012
- recordedReviewBatch = recordResult.reviewBatch ?? null;
3013
- }
3014
- const compactReviewBatch = {
3015
- tableId: campaignTableId ?? null,
3016
- rowCount: recordedReviewBatch?.rowCount ?? reviewBatchRowIds.length,
3017
- rowIds: recordedReviewBatch?.rowIds ?? reviewBatchRowIds,
3018
- enrichCellIds: recordedReviewBatch?.enrichCellIds ?? reviewBatchEnrichCellIds,
3019
- basisHash: recordedReviewBatch?.basisHash ?? null,
3020
- recordedAt: recordedReviewBatch?.recordedAt ?? null,
3021
- };
3022
- const importSummary = {
3023
- workflowTableId: campaignTableId ?? null,
3024
- campaignTableId: campaignTableId ?? null,
3025
- campaignTableName: importResult.campaignTableName ?? null,
3026
- leadsImported: importResult.leadsImported ?? null,
3027
- leadsSkipped: importResult.leadsSkipped ?? null,
3028
- rowCount: importResult.rowCount ?? importedRowCount,
3029
- requestedTargetLeadCount: importResult.requestedTargetLeadCount ?? null,
3030
- sourceRowLimit: importResult.sourceRowLimit ?? null,
3031
- async: importResult.async ?? false,
3032
- hybrid: importResult.hybrid ?? false,
3033
- campaignTableReady,
3034
- importStatus: importResult.importStatus ?? null,
3035
- remainingRowCount,
3036
- sourceRowCount: importResult.sourceRowCount ?? null,
3037
- clonedSourceRowCount: importResult.clonedSourceRowCount ?? null,
3038
- };
3039
2991
  // Persist currentStep if the caller asked for it. Do NOT touch
3040
2992
  // selectedLeadListId here: the campaign table id is already saved to
3041
2993
  // CampaignOffer.workflowTableId by /api/v3/campaign-builder/import-leads,
@@ -3062,9 +3014,7 @@ export async function confirmLeadList(input) {
3062
3014
  return {
3063
3015
  sourceLeadListId: resolvedLeadListId,
3064
3016
  campaignTableId: campaignTableId ?? null,
3065
- importSummary,
3066
- ...(includeRawImportResult ? { importResult } : {}),
3067
- reviewBatch: compactReviewBatch,
3017
+ importResult,
3068
3018
  messageDraftBuilder: {
3069
3019
  firstAllowedStartPoint: "confirm_lead_list",
3070
3020
  startAllowed: true,
@@ -3073,8 +3023,7 @@ export async function confirmLeadList(input) {
3073
3023
  campaignOfferId,
3074
3024
  selectedLeadListId: resolvedLeadListId,
3075
3025
  workflowTableId: campaignTableId ?? null,
3076
- reviewBatchRowIds,
3077
- reviewBatchBasisHash: compactReviewBatch.basisHash,
3026
+ reviewBatchRowIds: importedRowIds.slice(0, keptReviewRowCount),
3078
3027
  reviewBatchRowCount: keptReviewRowCount,
3079
3028
  copiedCampaignRowCount: importedRowCount,
3080
3029
  },
@@ -315,7 +315,7 @@ export function getPostFindLeadsScoutRegistry() {
315
315
  "basis.workflowTableId",
316
316
  "basis.reviewSampleRowHash or basis.reviewSampleRowIds",
317
317
  ],
318
- promptRequired: 'get_subskill_prompt({ subskillName: "generate-messages-compact" }); load generate-messages-compact/references/examples-critique-revision.md only for critique, revision, or close-call examples',
318
+ promptRequired: 'get_subskill_prompt({ subskillName: "generate-messages", offset, limit }) until hasMore=false',
319
319
  basisFields: [
320
320
  "campaign revision or updatedAt",
321
321
  "brief hash",
@@ -342,7 +342,7 @@ export function getPostFindLeadsScoutRegistry() {
342
342
  usage: {
343
343
  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 returned post-lead scout names before that question. Once the user answers, spawn Message Draft Builder from the same campaign/table basis. If the user chooses filters, also spawn Lead Fit Builder, move to Filter Rules, save rubrics, ask for filter approval, then keep the browser on Filter Leads and show `Filters saved + waiting for message approval` while the message recommendation is reviewed. If filters are skipped, move to Messages/message review.",
344
344
  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 returned post-lead Task/Agent names before that question. Once the user answers, invoke Message Draft Builder from the same campaign/table basis. If the user chooses filters, also invoke Lead Fit Builder, move to Filter Rules, save rubrics, ask for filter approval, then keep the browser on Filter Leads and show `Filters saved + waiting for message approval` while the message recommendation is reviewed. If filters are skipped, move to Messages/message review.",
345
- parentThreadRule: 'Named agents are optional acceleration, but message drafting is not optional. If post-find-leads-message-scout is available, run it as the background Message Draft Builder after the filter-choice answer. If it is absent, do not customer-surface install status; the main thread must execute the same message branch from CampaignOffer state, selected source state, workflowTableId, and initial campaign-table execution slice rows. 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, filter references, or the full legacy generate-messages prompt before it. Message drafting starts after the filter-choice answer, must load get_subskill_prompt({ subskillName: "generate-messages-compact" }), must read live campaign table state through scoped MCP/product tools, and must reject mismatched selectedLeadListId/workflowTableId/campaign/workspace input. Load generate-messages-compact/references/examples-critique-revision.md only for critique, revision, or close-call examples. On the filter path, keep the browser on Filter Rules after save_rubrics so the user can approve the saved criteria; only then move to Filter Leads, show `Filters saved + waiting for message approval`, and 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 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-compact prompt ran for the current campaign/table execution slice. 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
+ parentThreadRule: 'Named agents are optional acceleration, but message drafting is not optional. If post-find-leads-message-scout is available, run it as the background Message Draft Builder after the filter-choice answer. If it is absent, do not customer-surface install status; the main thread must execute the same message branch from CampaignOffer state, selected source state, workflowTableId, and initial campaign-table execution slice rows. 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, filter references, or the full generate-messages prompt before it. Message drafting starts after the filter-choice answer, must load get_subskill_prompt({ subskillName: "generate-messages", offset, limit }) until hasMore=false, must read live campaign table state through scoped MCP/product tools, and must reject mismatched selectedLeadListId/workflowTableId/campaign/workspace input. On the filter path, keep the browser on Filter Rules after save_rubrics so the user can approve the saved criteria; only then move to Filter Leads, show `Filters saved + waiting for message approval`, and 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 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 full generate-messages prompt ran for the current campaign/table execution slice. 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.',
346
346
  },
347
347
  };
348
348
  }