@sellable/mcp 0.1.127 → 0.1.129

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.
@@ -515,6 +515,12 @@
515
515
  "sales-nav-general",
516
516
  "prospeo"
517
517
  ],
518
+ "userFacingFallbackOrder": [
519
+ "people engaging with relevant LinkedIn posts",
520
+ "Sales Nav to find ICP people actively posting on LinkedIn",
521
+ "search by titles",
522
+ "Prospeo for a broader account/contact path."
523
+ ],
518
524
  "sourceDirectionOverrides": {
519
525
  "postEngagement": "signal-discovery",
520
526
  "creatorOrCommentSignals": "signal-discovery",
@@ -526,6 +532,13 @@
526
532
  "explicitCompare": "compare-requested-sources"
527
533
  },
528
534
  "quickViabilityRule": "Run only enough of the current lane to decide whether it can supply relevant, reachable ICP-looking leads. For Signals, viability requires sampled ICP-fit rate normalized to good-fit prospects per 100 engagers, required engagers to scrape, average reachable engagers per right-content post, projected good-fit prospects per post after cleanup, and posts-needed math against the 300-good-fit source target, not raw post count or the 15-row review-batch import limit. Stop on the first viable source unless the user asked for comparison.",
535
+ "sourceFailureHandling": [
536
+ "timeout/error: try the next approved lane or ask the user to revise the source/target before import",
537
+ "zero raw results: try the next approved lane or ask the user to revise the source/target before import",
538
+ "weak ICP fit: try the next approved lane or ask the user to revise the source/target before import",
539
+ "weak message context: try the next approved lane or ask the user to revise the source/target before import"
540
+ ],
541
+ "allLanesFailedState": "revise-source",
529
542
  "parallelAllowedOnlyWhen": [
530
543
  "user explicitly requested source comparison",
531
544
  "resuming already-started parallel scouts",
@@ -547,8 +560,9 @@
547
560
  },
548
561
  "when": "before_sequential_source_funnel",
549
562
  "requiresVisibleCheckpointBeforeProviderLane": true,
563
+ "askApprovalBeforeFirstLane": true,
550
564
  "forbidDirectPlanToProviderLane": true,
551
- "chatRenderRule": "Move the campaign watch view to the Pick Provider step before the main thread starts source viability work. This must be a distinct visible checkpoint: do not jump directly from Plan to Signal Discovery, Sales Nav, Prospeo, or another provider lane in the same visible beat. While the watched browser is on Pick Provider, explain the source-selection logic. If the user did not specify a source, explain the default order: start with warm LinkedIn post engagement because it gives stronger message context and expected reply-rate upside when enough ICP-looking engagers exist; if it is not viable, switch to Sales Nav with recent activity, then broader Sales Nav, and use Prospeo only as the fallback. If starting with Signal Discovery, explicitly say this is a viability test: Codex will look for relevant posts, sample engagers, estimate ICP fit, and only continue if the source math works. If the user did specify hiring signals, domains/accounts, supplied lists, posts/comments, or titles/personas, explain that the matching source overrides the default funnel. State that no leads import until a source is approved. The watchNarration headline/body must name the first lane being considered, why this lane now, the quick viability gate, and the safety boundary. Do not mention MCP or local artifacts."
565
+ "chatRenderRule": "Move the campaign watch view to the Pick Provider step before the main thread starts source viability work. This must be a distinct visible checkpoint: do not jump directly from Plan to Signal Discovery, Sales Nav, Prospeo, or another provider lane in the same visible beat. While the watched browser is on Pick Provider, explain the source-selection logic and ask for approval before starting Signal Discovery or a user-directed first lane. If the user did not specify a source, explain the default order in plain language: people engaging with relevant LinkedIn posts, then Sales Nav to find ICP people actively posting on LinkedIn, then search by titles, then Prospeo for a broader account/contact path. Keep the legacy provider mapping clear: Signal Discovery first, then Sales Nav with recent activity, then broader Sales Nav, and Prospeo only as the fallback. If starting with Signal Discovery, explicitly say this is a viability test: Codex will look for relevant posts, sample engagers, estimate ICP fit, and only continue if the source math works. If the user did specify hiring signals, domains/accounts, supplied lists, posts/comments, or titles/personas, explain that the matching source overrides the default funnel and still needs user approval before the lane starts. State that no leads import until a source is approved. The watchNarration headline/body must name the first lane being considered, why this lane now, the quick viability gate, and the safety boundary. Do not mention MCP or local artifacts."
552
566
  },
553
567
  {
554
568
  "action": "advance_watch_to_initial_source_lane",
@@ -949,9 +963,10 @@
949
963
  "targetLeadCountFromConfig": "sourceTargetGoodFitLeadCount (default 300) for provider source-list materialization, not import.importLimit",
950
964
  "signalDiscoveryRequiredFields": [
951
965
  "targetEngagerCount from approved source math",
952
- "maxPostsToScrape or selected post plan when available"
966
+ "approved promoted post ids selected with select_promising_posts",
967
+ "maxPostsToScrape from approved source math"
953
968
  ],
954
- "signalDiscoveryRule": "For Signal Discovery, pass targetEngagerCount = ceil(sourceTargetGoodFitLeads / sampledFitRateAfterCleanup) and maxPostsToScrape = postsNeeded when known. This prevents import_leads from scraping every selected/promoted sample post by default. The first campaign review batch is still limited by confirm_lead_list targetLeadCount import.importLimit.",
969
+ "signalDiscoveryRule": "For Signal Discovery, promote/select the exact approved posts with select_promising_posts before import_leads. Then pass targetEngagerCount = ceil(sourceTargetGoodFitLeads / sampledFitRateAfterCleanup) and maxPostsToScrape = postsNeeded from the approved source math. If no approved promoted posts are attached to the campaign, stop and route back to find-leads; do not import from unpromoted sample/search results. The first campaign review batch is still limited by confirm_lead_list targetLeadCount import.importLimit.",
955
970
  "onZeroLeads": "escalate_hard_fail",
956
971
  "modeAddHandshake": {
957
972
  "firstCallReturns": "needsModeSelection=true + existingLeadListId",
@@ -962,7 +977,8 @@
962
977
  "defaultBranch": "normal-discovery",
963
978
  "skipWhen": "resolved source branch returns sourceLeadListId for confirm_lead_list",
964
979
  "requiredBeforeCall": [
965
- "campaign_attached_source_state"
980
+ "campaign_attached_source_state",
981
+ "for Signal Discovery: approved_promoted_posts_attached_to_campaign"
966
982
  ]
967
983
  },
968
984
  {
@@ -1001,6 +1017,18 @@
1001
1017
  "stripCarryData": true,
1002
1018
  "sampleSizeFromConfig": "sample.sampleSize (15)"
1003
1019
  },
1020
+ {
1021
+ "action": "require_non_empty_review_batch_before_filter_choice",
1022
+ "after": "get_rows_minimal",
1023
+ "blocksCurrentStep": "filter-choice",
1024
+ "onZeroRows": "source-import-recovery",
1025
+ "recoveryChoices": [
1026
+ "retry import",
1027
+ "import more from approved source",
1028
+ "revise source"
1029
+ ],
1030
+ "rule": "If confirm_lead_list succeeds but get_rows_minimal returns zero imported review-batch rows, do not advance to filter-choice. Keep the user in source/import recovery and ask for retry import, import more from the approved source, or revise source."
1031
+ },
1004
1032
  {
1005
1033
  "tool": "update_campaign",
1006
1034
  "requiredFields": [
@@ -1013,7 +1041,7 @@
1013
1041
  "watchNarration.stage": "fit-message",
1014
1042
  "watchNarration.headline": "Added to Campaign"
1015
1043
  },
1016
- "watchNarrationRule": "After the bounded review batch is present, update the watched guide to `Added to Campaign`. Say Codex is adding fit filters so every send stays qualified while drafting the first message in the background. This persists add-filters intent by currentStep/watchNarration only; do not set enableICPFilters=true until save_rubrics succeeds with active criteria. Nothing enriches, validates, or sends until the first message is ready and approved."
1044
+ "watchNarrationRule": "After the bounded review batch is present and non-empty, update the watched guide to `Added to Campaign` and ask the user to Choose filters or skip. This is filter intent only: do not say filtering the batch before rubrics are saved. The Message Draft Builder may start in the background, but template review is locked until the filter path is reconciled and the user later chooses Use Template. Do not set enableICPFilters=true until save_rubrics succeeds with active criteria. Nothing enriches, validates, or sends until the user approves the message mode and template/token rules where applicable."
1017
1045
  }
1018
1046
  ],
1019
1047
  "allowedTools": [
@@ -1040,20 +1068,88 @@
1040
1068
  "watchRequired": true,
1041
1069
  "waitFor": "review_batch_imported",
1042
1070
  "transitions": {
1043
- "review_batch_imported": "post-lead-workstreams",
1071
+ "review_batch_imported": "filter-choice",
1044
1072
  "escalation_triggered": "escalation"
1045
1073
  },
1046
- "requiredArtifacts": [
1047
- "brief.md",
1048
- "lead-review.md",
1049
- "lead-sample.json"
1050
- ],
1074
+ "requiredArtifacts": [],
1051
1075
  "requiredCampaignState": [
1052
1076
  "campaignId",
1053
1077
  "providerSearchAssociation",
1054
1078
  "selectedLeadListId"
1055
1079
  ]
1056
1080
  },
1081
+ {
1082
+ "id": "filter-choice",
1083
+ "label": "Filter choice",
1084
+ "currentStepValue": "filter-choice",
1085
+ "normalFlow": true,
1086
+ "onEnter": [
1087
+ {
1088
+ "action": "show_filter_choice",
1089
+ "requiredVisibleContent": [
1090
+ "Choose filters or skip",
1091
+ "Use filters to keep only qualified leads",
1092
+ "Skip filters and continue to Messages",
1093
+ "active filtering starts only after rubrics are saved"
1094
+ ],
1095
+ "chatRenderRule": "The first post-import user gate is filter choice. Ask the user to Choose filters or skip. Make clear that active filtering starts only after rubrics are saved; do not say filtering the batch before rubrics are saved. If the user skips filters, go to Messages mode choice once the review batch is ready."
1096
+ },
1097
+ {
1098
+ "tool": "update_campaign",
1099
+ "requiredValues": {
1100
+ "currentStep": "filter-choice",
1101
+ "watchNarration.stage": "fit-message"
1102
+ },
1103
+ "watchNarrationRule": "Ask whether the user wants to further filter the imported leads. Say whether the selected lead list looks mixed/good/noisy based on the imported 15-row review batch, then ask Choose filters or skip. Do not say filtering the batch before rubrics are saved."
1104
+ },
1105
+ {
1106
+ "action": "persist_filters_enabled_choice",
1107
+ "tool": "update_campaign",
1108
+ "when": "immediately after the user chooses filters_enabled",
1109
+ "requiredValues": {
1110
+ "enableICPFilters": true,
1111
+ "currentStep": "create-icp-rubric",
1112
+ "watchNarration.stage": "fit-message"
1113
+ },
1114
+ "watchNarrationRule": "Move the watched app to Filter Rules and show passive copy that Codex is defining the filters in chat. Do not leave the user on filter-choice after they choose filters."
1115
+ }
1116
+ ],
1117
+ "allowedTools": [
1118
+ "AskUserQuestion",
1119
+ "request_user_input",
1120
+ "update_campaign",
1121
+ "get_campaign_navigation_state"
1122
+ ],
1123
+ "doNotAllow": [
1124
+ "create_campaign",
1125
+ "save_rubrics",
1126
+ "import_leads",
1127
+ "confirm_lead_list",
1128
+ "queue_cells",
1129
+ "start_campaign",
1130
+ "generate_messages",
1131
+ "enrich_with_prospeo",
1132
+ "bulk_enrich_with_prospeo"
1133
+ ],
1134
+ "watchRequired": true,
1135
+ "waitFor": [
1136
+ "filters_enabled",
1137
+ "filters_skipped",
1138
+ "revise_leads"
1139
+ ],
1140
+ "transitions": {
1141
+ "filters_enabled": "post-lead-workstreams",
1142
+ "filters_skipped": "messages-mode-choice",
1143
+ "revise_leads": "find-leads"
1144
+ },
1145
+ "interruptOnly": true,
1146
+ "requiredCampaignState": [
1147
+ "campaignId",
1148
+ "campaignBrief",
1149
+ "selectedLeadListId",
1150
+ "workflowTableId"
1151
+ ]
1152
+ },
1057
1153
  {
1058
1154
  "id": "post-lead-workstreams",
1059
1155
  "label": "Post-import filter and message workstreams",
@@ -1073,9 +1169,9 @@
1073
1169
  "name": "filter-leads",
1074
1170
  "target": "filter-leads",
1075
1171
  "inputs": [
1076
- "brief.md",
1077
- "lead-review.md",
1078
- "lead-sample.json",
1172
+ "campaignBrief",
1173
+ "selected source decision",
1174
+ "selectedLeadListId",
1079
1175
  "workflowTableId review-batch rows"
1080
1176
  ],
1081
1177
  "producesArtifacts": [
@@ -1091,29 +1187,33 @@
1091
1187
  "target": "generate-messages",
1092
1188
  "mode": "DRY MODE",
1093
1189
  "inputs": [
1094
- "brief.md",
1095
- "lead-review.md",
1096
- "lead-sample.json",
1190
+ "campaignBrief",
1191
+ "selected source decision",
1192
+ "selectedLeadListId",
1097
1193
  "workflowTableId review-batch rows"
1098
1194
  ],
1099
1195
  "producesArtifacts": [
1100
- "message-validation.md"
1196
+ "template recommendation",
1197
+ "token fill rules",
1198
+ "rendered sample"
1101
1199
  ],
1102
1200
  "optionalProducesArtifacts": [
1201
+ "message-validation.md",
1103
1202
  "message-prep.md",
1104
1203
  "message-candidate-drafts.md"
1105
1204
  ],
1106
1205
  "ownership": "proof inventory, token strategy, angle drafting, skeptical-prospect review, and selected winner only"
1107
1206
  }
1108
1207
  ],
1109
- "earlyMessageStartRule": "After auto-execute-leads confirms the 15-row review batch and workflowTableId is ready, launch message-generation from brief.md, lead-review.md, lead-sample.json, and the imported campaign table sample. The message worker carries the campaign-launch message rules in its agent prompt; parent-thread fallback loads references/message-review-safety-gate.md. Legacy/resume preview prep still requires at least 3 probable good-fit rows. It may run beside filter-leads, but the cascade cannot queue until save_rubrics and update_campaign_brief both succeed.",
1110
- "finalMessageReconcileRule": "message-validation.md may start before lead-filter.md exists, but before message-review it must cite only imported review-batch rows that still pass lead-filter.md. If the selected winner depends on a row later excluded by lead-filter.md, revise message-generation before message review.",
1208
+ "earlyMessageStartRule": "After auto-execute-leads confirms the 15-row review batch, workflowTableId is ready, and the user has reached filter choice, the Message Draft Builder may start from campaignBrief, selected source state, selectedLeadListId, and imported campaign table rows, including while the user is on filter choice. This background template draft is provisional speed work only. The message worker must load the full generate-messages prompt; parent-thread fallback loads the same prompt and may use references/message-review-safety-gate.md only as a supplemental approval checklist. Legacy/resume preview prep still requires at least 3 probable good-fit rows. It may run beside filter-leads, but product Generate Message cells cannot queue until save_rubrics and update_campaign_brief both succeed.",
1209
+ "finalMessageReconcileRule": "The message recommendation may start before lead-filter.md exists, but before message-review it must cite only imported review-batch rows that still pass the saved rubric/filter results. If the selected winner depends on a row later excluded by saved filters, revise message-generation before message review.",
1210
+ "finalTemplateReviewLockRule": "cannot start template review until filter choice is answered and the user chooses Use Template in Messages. If filters are enabled, lock template review until saved rubrics exist, a bounded filter run has completed, and there are usable passing/probably passing rows. prefer at least 2 usable passing rows for template review; if only 1 passes, show weak-sample copy and ask whether to continue, revise, import more, or skip filters. If filters are skipped, route to Messages mode choice once the review batch is ready. AI Generated is an explicit opt-out and must cancel or ignore the background template draft.",
1111
1211
  "claudeRule": "In Claude Code, launch both returned post-find-leads scouts with Task/Agent subagents in the same assistant message only when the current session lists those agent names. Do not run filter first and then message generation unless subagents/background work are unavailable.",
1112
1212
  "codexRule": "In Codex, launch both returned post-find-leads scout names as disjoint subagents in the same assistant turn only when the host exposes those custom agents for this run. If the host cannot spawn them, run the same branches sequentially and say so.",
1113
1213
  "fallback": "If real parallel branches are unavailable or the named agents are absent, run filter-leads and then message-generation in the parent thread with product MCP tools/assets. Do not customer-surface agent install status, and do not claim background or parallel work in that fallback."
1114
1214
  },
1115
1215
  {
1116
- "action": "wait_for_lead_filter_artifact",
1216
+ "action": "wait_for_lead_filter_rules",
1117
1217
  "requiredArtifacts": [
1118
1218
  "lead-filter.md"
1119
1219
  ],
@@ -1123,7 +1223,7 @@
1123
1223
  "message-prep.md",
1124
1224
  "message-candidate-drafts.md"
1125
1225
  ],
1126
- "rule": "Do not wait for message-validation.md before saving rubrics and moving the watched browser to Filter Leads. Message work may still be running while the user watches fit filtering."
1226
+ "rule": "Do not wait for message-validation.md before saving rubrics and moving the watched browser to Filter Leads. lead-filter.md is a debug artifact name; the durable requirement is production-safe rubric rules derived from the live campaign table review batch. Message work may still be running while the user watches fit filtering."
1127
1227
  },
1128
1228
  {
1129
1229
  "action": "save_filter_rubrics_to_campaign",
@@ -1161,28 +1261,67 @@
1161
1261
  "when": "after_save_rubrics_succeeds_before_waiting_for_message_validation",
1162
1262
  "writesCampaignState": "currentStep:apply-icp-rubric"
1163
1263
  },
1264
+ {
1265
+ "tool": "get_rows_minimal",
1266
+ "requiredValues": {
1267
+ "tableId": "workflowTableId",
1268
+ "limit": "import.importLimit"
1269
+ },
1270
+ "purpose": "read_bounded_review_batch_cell_ids_before_filter_wait",
1271
+ "requiredBeforeCascade": true
1272
+ },
1273
+ {
1274
+ "tool": "queue_cells",
1275
+ "requiredValues": {
1276
+ "tableId": "workflowTableId",
1277
+ "cellSource": "bounded_review_batch_enrichCellIds",
1278
+ "statusFilter": [
1279
+ "pending",
1280
+ "error",
1281
+ "dependency_blocked"
1282
+ ]
1283
+ },
1284
+ "purpose": "queue_bounded_review_batch_enrichment_before_waiting_for_rubric_results",
1285
+ "rule": "Queue only enrichCellId values from get_rows_minimal for the bounded review batch. Do not queue icpCellId values or whole-table cells; the workflow cascade runs ICP scoring after enrichment."
1286
+ },
1287
+ {
1288
+ "tool": "wait_for_rubric_results",
1289
+ "requiredValues": {
1290
+ "includeRows": false,
1291
+ "minPassedCount": 1,
1292
+ "targetCount": "bounded review batch count"
1293
+ },
1294
+ "purpose": "wait_for_bounded_filter_run_before_messages_mode",
1295
+ "readVia": "stats_only_tool_result",
1296
+ "note": "After filtered sample passes, Messages first shows mode choice. Prefer at least 2 usable passing/probably passing rows before Use Template review; if only 1 passes, show weak-sample copy and ask whether to continue, revise, import more, or skip filters."
1297
+ },
1298
+ {
1299
+ "action": "require_usable_filtered_rows_before_messages_mode",
1300
+ "after": "wait_for_rubric_results",
1301
+ "requiredBeforeMessagesMode": true,
1302
+ "rule": "If filters are enabled, do not show template review until saved rubrics and a bounded filter run have usable passing/probably passing rows. After the filtered sample passes, route to Messages mode choice before any template review."
1303
+ },
1164
1304
  {
1165
1305
  "tool": "get_campaign_navigation_state",
1166
1306
  "purpose": "confirm the watched UI moved to Filter Leads after rubrics saved",
1167
1307
  "optional": true
1168
1308
  },
1169
1309
  {
1170
- "action": "wait_for_message_validation_artifact",
1171
- "requiredArtifacts": [
1172
- "message-validation.md"
1310
+ "action": "wait_for_message_draft_recommendation",
1311
+ "requiredOutputs": [
1312
+ "template recommendation",
1313
+ "token fill rules",
1314
+ "rendered sample"
1173
1315
  ],
1174
1316
  "optionalArtifacts": [
1317
+ "message-validation.md",
1175
1318
  "message-prep.md",
1176
1319
  "message-candidate-drafts.md"
1177
1320
  ],
1178
- "reconciliationRule": "Before entering message-review, verify message-validation.md came from the same brief.md, lead-review.md, lead-sample.json, and saved lead-filter.md. lead-filter.md gates the sample rows; lead-sample.json remains the message sample source."
1321
+ "reconciliationRule": "Before entering message-review, verify the recommendation came from the same campaignBrief, selected source state, selectedLeadListId, imported review-batch rows, and saved filters. Saved filters gate the sample rows; debug markdown files are optional only."
1179
1322
  }
1180
1323
  ],
1181
- "requiredArtifacts": [
1182
- "brief.md",
1183
- "lead-review.md",
1184
- "lead-sample.json"
1185
- ],
1324
+ "requiredArtifacts": [],
1186
1325
  "producesArtifacts": [
1187
1326
  "lead-filter.md",
1188
1327
  "message-validation.md"
@@ -1197,6 +1336,9 @@
1197
1336
  "get_subskill_asset",
1198
1337
  "get_post_find_leads_scout_registry",
1199
1338
  "save_rubrics",
1339
+ "get_rows_minimal",
1340
+ "queue_cells",
1341
+ "wait_for_rubric_results",
1200
1342
  "update_campaign",
1201
1343
  "get_campaign_navigation_state",
1202
1344
  "Task",
@@ -1206,16 +1348,16 @@
1206
1348
  ],
1207
1349
  "toolRules": [
1208
1350
  "The post-lead workstreams are disjoint: filter-leads owns lead-filter.md/rubric.json; message-generation owns message-validation.md/message-prep.md/message-candidate-drafts.md.",
1209
- "message-generation can start before lead-filter.md, but message-review cannot start until both lead-filter.md and message-validation.md exist and reconcile against the same lead-sample.json.",
1351
+ "message-generation can start before saved filters, but message-review cannot start until saved filters and the message recommendation reconcile against the same imported review-batch rows.",
1210
1352
  "Do not let filter-leads create a new message sample. Do not let message-generation fetch new prospects.",
1211
- "Before writing message-validation.md, message-generation must either run in the post-find-leads-message-scout agent that carries the campaign-launch message rules in its prompt or load get_subskill_asset({ subskillName: \"create-campaign-v2\", assetPath: \"references/message-review-safety-gate.md\" }) in the parent-thread fallback. Do not load the full long generate-messages prompt in create-campaign-v2; if the safety gate cannot safely approve the draft, route to revise-messaging with the concrete failure.",
1212
- "Do not queue, enrich, attach sequence, or start until save_rubrics succeeds and the approved message set is synced into campaignBrief."
1353
+ "Before writing message-validation.md or returning a template recommendation, message-generation must load the full get_subskill_prompt({ subskillName: \"generate-messages\" }) prompt and use campaignBrief, selected source state, selectedLeadListId, and imported review-batch rows as the source of truth. Optional debug markdown files are not durable state.",
1354
+ "Do not queue before saved rubrics. After save_rubrics succeeds, queue only bounded review-batch enrichCellId values from get_rows_minimal before wait_for_rubric_results.",
1355
+ "Do not attach sequence, start, or queue product Generate Message cells until the approved message set is synced into campaignBrief."
1213
1356
  ],
1214
1357
  "doNotAllow": [
1215
1358
  "create_campaign",
1216
1359
  "import_leads",
1217
1360
  "confirm_lead_list",
1218
- "queue_cells",
1219
1361
  "start_campaign",
1220
1362
  "check_rubric",
1221
1363
  "generate_messages",
@@ -1231,15 +1373,17 @@
1231
1373
  "confirm_with_user"
1232
1374
  ],
1233
1375
  "transitions": {
1234
- "post_lead_workstreams_ready": "message-review",
1376
+ "post_lead_workstreams_ready": "messages-mode-choice",
1235
1377
  "revise_leads": "find-leads",
1236
1378
  "revise_rubric": "filter-rubric",
1237
1379
  "revise_messaging": "message-generation",
1238
- "confirm_with_user": "message-review"
1380
+ "confirm_with_user": "messages-mode-choice"
1239
1381
  },
1240
1382
  "interruptOnly": true,
1241
1383
  "requiredCampaignState": [
1242
1384
  "campaignId",
1385
+ "campaignBrief",
1386
+ "selectedLeadListId",
1243
1387
  "workflowTableId"
1244
1388
  ],
1245
1389
  "debugProducesArtifacts": [
@@ -1250,6 +1394,88 @@
1250
1394
  "message-candidate-drafts.md"
1251
1395
  ]
1252
1396
  },
1397
+ {
1398
+ "id": "messages-mode-choice",
1399
+ "label": "Messages mode choice",
1400
+ "currentStepValue": "messages",
1401
+ "normalFlow": true,
1402
+ "onEnter": [
1403
+ {
1404
+ "tool": "update_campaign",
1405
+ "requiredValues": {
1406
+ "currentStep": "messages",
1407
+ "watchNarration.stage": "fit-message"
1408
+ },
1409
+ "watchNarrationRule": "Messages first shows a mode choice, not final review: Use Template and AI Generated. Use Template is recommended because it uses the approved campaign brief and review-batch evidence. AI Generated is an explicit opt-out from the background template draft. Do not show Review fit and message until the user chooses a mode and a reviewable message/template exists."
1410
+ },
1411
+ {
1412
+ "action": "show_messages_mode_choice",
1413
+ "choices": [
1414
+ "Use Template (recommended)",
1415
+ "AI Generated"
1416
+ ],
1417
+ "copyRule": "Show Use Template first and mark it recommended. Explain that Use Template reviews the Message Draft Builder template before any Generate Message cells run. Explain that AI Generated is an explicit opt-out."
1418
+ },
1419
+ {
1420
+ "action": "wait_for_message_draft_builder_when_use_template",
1421
+ "when": "user chose Use Template and draft is not ready",
1422
+ "copy": "I am waiting for the Message Draft Builder. I will show the template when it is ready; I am not asking for approval yet.",
1423
+ "forbiddenApprovalCopy": true
1424
+ },
1425
+ {
1426
+ "action": "handle_unusable_or_unknown_template_draft",
1427
+ "when": "draft worker fails, produces no usable message, or worker status is unknown",
1428
+ "requiredCopy": "retry or regenerate the template draft before approval",
1429
+ "forbiddenApprovalCopy": true
1430
+ },
1431
+ {
1432
+ "action": "cancel_or_ignore_background_template_on_ai_generated",
1433
+ "when": "user chose AI Generated",
1434
+ "rule": "AI Generated is an explicit opt-out: cancel or ignore the background template draft and must not let late background template draft output overwrite campaign state."
1435
+ },
1436
+ {
1437
+ "action": "route_ai_generated_to_product_path",
1438
+ "when": "user chose AI Generated",
1439
+ "rule": "Continue through the explicit AI-generated product path. Route to auto-execute-messaging when product row generation is required first; do not transition to validate-sample as the normal path."
1440
+ }
1441
+ ],
1442
+ "allowedTools": [
1443
+ "AskUserQuestion",
1444
+ "request_user_input",
1445
+ "update_campaign",
1446
+ "get_campaign_navigation_state"
1447
+ ],
1448
+ "doNotAllow": [
1449
+ "create_campaign",
1450
+ "import_leads",
1451
+ "confirm_lead_list",
1452
+ "queue_cells",
1453
+ "start_campaign",
1454
+ "generate_messages",
1455
+ "enrich_with_prospeo",
1456
+ "bulk_enrich_with_prospeo"
1457
+ ],
1458
+ "watchRequired": true,
1459
+ "waitFor": [
1460
+ "use_template_ready",
1461
+ "use_template_waiting",
1462
+ "ai_generated_selected",
1463
+ "revise_messaging"
1464
+ ],
1465
+ "transitions": {
1466
+ "use_template_ready": "message-review",
1467
+ "use_template_waiting": "message-generation",
1468
+ "ai_generated_selected": "auto-execute-messaging",
1469
+ "revise_messaging": "message-generation"
1470
+ },
1471
+ "interruptOnly": true,
1472
+ "requiredCampaignState": [
1473
+ "campaignId",
1474
+ "campaignBrief",
1475
+ "selectedLeadListId",
1476
+ "workflowTableId"
1477
+ ]
1478
+ },
1253
1479
  {
1254
1480
  "id": "filter-rubric",
1255
1481
  "label": "Lead filters and production rubrics",
@@ -1374,41 +1600,38 @@
1374
1600
  "onEnter": [
1375
1601
  {
1376
1602
  "action": "run_or_reconcile_subskill",
1377
- "target": "message-review-safety-gate",
1603
+ "target": "generate-messages",
1378
1604
  "mode": "DRY MODE",
1379
- "sampleSource": "lead-sample.json from find-leads",
1605
+ "sampleSource": "imported review-batch rows from selectedLeadListId",
1380
1606
  "toolCallRequiredBeforeArtifacts": [
1381
- "get_subskill_asset({ subskillName: \"create-campaign-v2\", assetPath: \"references/message-review-safety-gate.md\" }) unless the post-find-leads-message-scout agent prompt already supplied these rules"
1607
+ "get_subskill_prompt({ subskillName: \"generate-messages\", offset, limit }) until hasMore=false",
1608
+ "optional supplemental check: get_subskill_asset({ subskillName: \"create-campaign-v2\", assetPath: \"references/message-review-safety-gate.md\" })"
1382
1609
  ],
1383
- "skipIfFreshArtifactExists": "message-validation.md",
1384
- "reconcileWith": "lead-filter.md; lead-sample.json remains the sample source"
1610
+ "skipIfFreshStateExists": "fresh messageDraftRecommendation from the same campaign/source/review-batch basis",
1611
+ "reconcileWith": "saved filters and imported review-batch rows; optional lead-filter.md only mirrors those filters"
1385
1612
  },
1386
1613
  {
1387
- "action": "write_artifact",
1388
- "artifact": "message-validation.md"
1614
+ "action": "return_template_recommendation",
1615
+ "optionalArtifact": "message-validation.md"
1389
1616
  }
1390
1617
  ],
1391
- "requiredArtifacts": [
1392
- "brief.md",
1393
- "lead-review.md",
1394
- "lead-sample.json"
1395
- ],
1618
+ "requiredArtifacts": [],
1396
1619
  "producesArtifacts": [
1397
1620
  "message-validation.md"
1398
1621
  ],
1399
1622
  "allowedTools": [
1623
+ "get_subskill_prompt",
1400
1624
  "get_subskill_asset",
1401
1625
  "AskUserQuestion",
1402
1626
  "request_user_input"
1403
1627
  ],
1404
1628
  "toolRules": [
1405
- "Before writing message-validation.md, message-review.md, or a message-review AskUserQuestion, the current run must either execute inside the post-find-leads-message-scout agent that carries the campaign-launch message rules in its prompt or load get_subskill_asset({ subskillName: \"create-campaign-v2\", assetPath: \"references/message-review-safety-gate.md\" }) in the parent-thread fallback.",
1406
- "Lead Sample Basis must cite rows from lead-sample.json produced by find-leads. lead-filter.md only gates those rows; it is not a source for a new sample.",
1407
- "Do not hand-write message-validation.md from message-prep.md, message-candidate-drafts.md, or general campaign knowledge.",
1408
- "message-validation.md must prove the message-review safety-gate workflow ran: Gold Standard Strategy Map, Campaign Element Pool, Current Campaign Translation, Token Fill Rules, Token Adherence Table, Angle Drafts, Kill / Combine Review, Finalizer Pass, Gold-Standard Quality Gate, Skeptical Prospect Review, Winner Gate, and a raw sendable Selected Winner are required before message-review can recommend approve-message.",
1409
- "If the hosted output is plausible but weaker than the safety-gate gold-standard rules, stop at message-review with revise-messaging. Do not continue to approval or mint just because the mechanical flow worked.",
1410
- "Do not load the full generate-messages subskill in create-campaign-v2. If the safety gate is missing a needed campaign-specific rule or the first safety-gate draft fails quality gates, route to revise-messaging with the concrete failure instead of loading the long prompt.",
1411
- "The approved message set must be written back into campaignBrief before validate-sample queues the review-batch cascade."
1629
+ "Before writing message-validation.md, message-review.md, or a message-review AskUserQuestion, load the full get_subskill_prompt({ subskillName: \"generate-messages\" }) prompt and draft from campaignBrief, selected source state, selectedLeadListId, and imported review-batch rows.",
1630
+ "Do not use brief.md, lead-review.md, or lead-sample.json as required live state; those files are optional debug context only.",
1631
+ "Do not hand-write message-validation.md from message-prep.md, message-candidate-drafts.md, stale markdown files, database reads, or general campaign knowledge.",
1632
+ "message-validation.md or the returned recommendation must prove the generate-messages workflow ran and include Token Fill Rules, good-fill and omit/fallback examples, a raw sendable selected winner, and quality gate notes before message-review can recommend approve-message.",
1633
+ "If the generate-messages output is plausible but weaker than the gold-standard rules, stop at message-review with revise-messaging. Do not continue to approval or mint just because the mechanical flow worked.",
1634
+ "The approved message set must be written back into campaignBrief before auto-execute-messaging observes or queues product Generate Message cells. AI Generated mode uses the product's AI-generated path instead of template review."
1412
1635
  ],
1413
1636
  "doNotAllow": [
1414
1637
  "create_campaign",
@@ -1445,6 +1668,8 @@
1445
1668
  "interruptOnly": true,
1446
1669
  "requiredCampaignState": [
1447
1670
  "campaignId",
1671
+ "campaignBrief",
1672
+ "selectedLeadListId",
1448
1673
  "workflowTableId"
1449
1674
  ]
1450
1675
  },
@@ -1455,15 +1680,18 @@
1455
1680
  "resumeOnly": false,
1456
1681
  "onEnter": [
1457
1682
  {
1458
- "action": "read_draft_artifacts",
1459
- "requiredFiles": [
1460
- "brief.md",
1461
- "lead-review.md",
1462
- "lead-sample.json",
1463
- "lead-filter.md",
1464
- "message-validation.md"
1683
+ "action": "read_live_message_recommendation",
1684
+ "requiredState": [
1685
+ "campaignBrief",
1686
+ "selected source state",
1687
+ "selectedLeadListId",
1688
+ "workflowTableId",
1689
+ "saved filters when filters are enabled",
1690
+ "template recommendation with token fill rules and rendered sample"
1465
1691
  ],
1466
- "optionalFiles": [
1692
+ "optionalDebugFiles": [
1693
+ "lead-filter.md",
1694
+ "message-validation.md",
1467
1695
  "message-prep.md",
1468
1696
  "message-candidate-drafts.md"
1469
1697
  ]
@@ -1582,13 +1810,12 @@
1582
1810
  "requires": [
1583
1811
  "campaignId",
1584
1812
  "message-review-decision.md",
1585
- "message-validation.md",
1586
- "lead-filter.md"
1813
+ "approved template recommendation",
1814
+ "saved filters when filters are enabled"
1587
1815
  ],
1588
- "when": "after_message_approved_before_import",
1816
+ "when": "after_message_approved_before_product_messaging",
1589
1817
  "fields": [
1590
- "campaignBrief with ## Approved Message Template, Token Fill Rules, Token Fill Examples",
1591
- "useMessagingTemplate:true"
1818
+ "campaignBrief with ## Approved Message Template containing {{...}} tokens, Token Fill Rules, Token Fill Examples"
1592
1819
  ],
1593
1820
  "requiredBeforeImport": false,
1594
1821
  "onFailure": "stop_before_import_or_enrichment",
@@ -1596,30 +1823,31 @@
1596
1823
  "writesCampaignState": "campaignBrief.Approved Message Template"
1597
1824
  },
1598
1825
  {
1599
- "action": "advance_watch_to_validation_after_message_approval",
1826
+ "action": "advance_watch_to_messaging_after_message_approval",
1600
1827
  "tool": "update_campaign",
1601
1828
  "requires": [
1602
1829
  "campaignId",
1603
1830
  "message-review-decision.md"
1604
1831
  ],
1605
1832
  "requiredValues": {
1606
- "currentStep": "validate-sample",
1833
+ "currentStep": "auto-execute-messaging",
1607
1834
  "enableICPFilters": true,
1608
- "useMessagingTemplate": true,
1609
1835
  "watchNarration.stage": "review-ready"
1610
1836
  },
1611
1837
  "when": "after_update_campaign_brief_succeeds",
1612
1838
  "requiredBeforeCascade": true,
1613
- "writesCampaignState": "currentStep:validate-sample"
1839
+ "writesCampaignState": "currentStep:auto-execute-messaging"
1614
1840
  }
1615
1841
  ],
1616
1842
  "requiredArtifacts": [
1617
1843
  "brief.md",
1618
1844
  "lead-review.md",
1619
1845
  "lead-sample.json",
1620
- "lead-filter.md",
1621
1846
  "message-validation.md"
1622
1847
  ],
1848
+ "optionalRequiredArtifacts": [
1849
+ "lead-filter.md"
1850
+ ],
1623
1851
  "producesArtifacts": [
1624
1852
  "message-review.md",
1625
1853
  "message-review-decision.md"
@@ -1647,14 +1875,13 @@
1647
1875
  "revise_messaging"
1648
1876
  ],
1649
1877
  "transitions": {
1650
- "message_approved": "validate-sample",
1878
+ "message_approved": "auto-execute-messaging",
1651
1879
  "revise_messaging": "message-generation"
1652
1880
  },
1653
1881
  "interruptOnly": true,
1654
1882
  "requiredCampaignState": [
1655
1883
  "campaignId",
1656
- "workflowTableId",
1657
- "leadScoringRubrics"
1884
+ "workflowTableId"
1658
1885
  ]
1659
1886
  },
1660
1887
  {
@@ -1933,8 +2160,7 @@
1933
2160
  "fields": [
1934
2161
  "campaignBrief",
1935
2162
  "leadSourceType",
1936
- "leadSourceProvider",
1937
- "useMessagingTemplate"
2163
+ "leadSourceProvider"
1938
2164
  ],
1939
2165
  "skipWhen": "create_campaign minted a new campaign with the final approved brief and currentStep already set"
1940
2166
  },
@@ -2025,6 +2251,9 @@
2025
2251
  "id": "validate-sample",
2026
2252
  "label": "Step 14: Validate 15-lead test batch",
2027
2253
  "currentStepValue": "validate-sample",
2254
+ "normalFlow": false,
2255
+ "resumeOnly": true,
2256
+ "deprecatedReason": "Recovery/legacy only. The normal Phase 135 path reaches Messages after the filtered sample passes, then routes Use Template approval or AI Generated choice to auto-execute-messaging.",
2028
2257
  "reference": "references/sample-validation-loop.md",
2029
2258
  "counter": {
2030
2259
  "name": "revisionRound",
@@ -2034,6 +2263,14 @@
2034
2263
  "capFromConfig": "sample.maxRevisionRounds"
2035
2264
  },
2036
2265
  "onEnter": [
2266
+ {
2267
+ "action": "resolve_messages_mode",
2268
+ "branches": {
2269
+ "use-template": "Use the approved template/token rules already synced into CampaignOffer.campaignBrief.",
2270
+ "ai-generated": "Use the explicit AI-generated product path and cancel or ignore any background template draft."
2271
+ },
2272
+ "rule": "AI Generated mode must not read, apply, or be overwritten by the background Message Draft Builder template."
2273
+ },
2037
2274
  {
2038
2275
  "action": "watch_mode_orient"
2039
2276
  },
@@ -2138,7 +2375,8 @@
2138
2375
  "first_passing_row_unblocks_generate_message_observation",
2139
2376
  "timeout_never_repeats_without_customer_handoff",
2140
2377
  "timeout_or_underfloor_sample_never_advances_to_settings",
2141
- "review_batch_cascade_waits_for_saved_rubrics_and_approved_template"
2378
+ "review_batch_cascade_waits_for_saved_rubrics_and_approved_template",
2379
+ "generate_message_cells_do_not_run_from_background_template_until_template_token_rules_approved"
2142
2380
  ],
2143
2381
  "watchRequired": true,
2144
2382
  "waitFor": [
@@ -2209,6 +2447,7 @@
2209
2447
  "action": "verify_campaign_brief_template_mode",
2210
2448
  "requiredSection": "Approved Message Template",
2211
2449
  "requiredPattern": "{{...}}",
2450
+ "skipWhen": "messageMode is ai-generated",
2212
2451
  "onFailure": "runtime_failure_before_messaging",
2213
2452
  "repairBoundary": "before_import_only",
2214
2453
  "purpose": "ensure Generate Message uses the approved template instead of full-generation mode"
@@ -2219,7 +2458,7 @@
2219
2458
  },
2220
2459
  {
2221
2460
  "tool": "queue_cells",
2222
- "cellSource": "pending_generate_message_cells_for_passing_rows",
2461
+ "cellSource": "pending_generate_message_cells_for_passing_rows; in ai-generated mode use the explicit AI-generated product path, not the background template draft",
2223
2462
  "when": "any passing row has pending or empty Generate Message cell",
2224
2463
  "batchSize": 100
2225
2464
  },
@@ -2269,7 +2508,9 @@
2269
2508
  "opus_reserved_for_highest_value_subset",
2270
2509
  "proposed_token_never_persisted_in_rewrite",
2271
2510
  "generate_messages_must_re_cascade_on_newly_passed_rows",
2272
- "campaign_brief_must_contain_approved_message_template_tokens_before_generate_message_cascade"
2511
+ "campaign_brief_must_contain_approved_message_template_tokens_before_generate_message_cascade",
2512
+ "ai_generated_mode_uses_explicit_product_path_and_ignores_background_template_draft",
2513
+ "generate_message_cells_do_not_run_from_background_template_until_template_token_rules_approved"
2273
2514
  ],
2274
2515
  "watchRequired": true,
2275
2516
  "waitFor": [