@sellable/mcp 0.1.126 → 0.1.128

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.
@@ -80,6 +80,9 @@ Quality bar:
80
80
 
81
81
  - Do not synthesize a lightweight message from general knowledge. The artifact
82
82
  must prove the embedded message-review safety-gate workflow ran.
83
+ - There is no generate-message fast mode in this path. The embedded gate is the
84
+ same campaign-launch quality contract used by the parent-thread compatibility
85
+ path, not a lower-quality shortcut.
83
86
  - Message generation can start before `lead-filter.md`, but message review
84
87
  cannot start until the parent verifies the selected basis rows still pass the
85
88
  final filter.
@@ -128,6 +131,13 @@ Quality gates:
128
131
  `[insert]`, or `[generated]`.
129
132
  - Optional row-specific personalization must be grounded in a row field or
130
133
  omitted entirely.
134
+ - Engagement-source personalization is a special case, not the default opener.
135
+ Do not write `saw you {{engagement_context}} on {{post_context}}`, `saw you
136
+ reacted to`, `saw you engaging with`, or equivalent source-citation copy as a
137
+ default hook. Only refer to the prospect's engagement when the line is
138
+ self-aware and low-certainty, for example `not sure if this is too specific,
139
+ but the [topic] thread felt close enough to send`. Otherwise omit the
140
+ engagement signal and use role/company/problem context.
131
141
  - Subjects should be short, buyer-relevant, and specific. Avoid `quick
132
142
  question`, `demo`, `founder call`, sender names, and generic `outbound`.
133
143
  - If the message is plausible but not ready to send, set `Recommendation:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.126",
3
+ "version": "0.1.128",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -71,8 +71,10 @@ Disk artifacts are optional debug/UAT diagnostics; normal customer runs should
71
71
  not create, link, or surface local draft files unless the user explicitly asks
72
72
  for them. Resume, gating, and handoff read campaign state first. The
73
73
  watchable campaign exists after the short brief; lead import is bounded to the
74
- first review batch, and enrichment/message generation waits until rubrics and
75
- the approved message template are saved on the campaign.
74
+ first review batch. After that, the user chooses whether to use filters or skip,
75
+ then Messages first shows Use Template and AI Generated. The Message Draft
76
+ Builder may work in the background, but template review waits for the filter
77
+ path and an explicit Use Template choice.
76
78
 
77
79
  ## Opening Turn Contract
78
80
 
@@ -145,9 +147,13 @@ registry pattern for the two post-lead branches. The create-campaign-v2 subskill
145
147
  calls `get_post_find_leads_scout_registry`, then launches the returned
146
148
  filter-leads scout and message-generation scout together when real subagents are
147
149
  available and the current session exposes the returned names. Message
148
- generation must not wait for the filter unless the host cannot run the two
149
- branches concurrently. If the post-lead agents are absent, the main thread still
150
- orchestrates the same branches from the compact context with MCP tools/assets.
150
+ generation is the provisional Message Draft Builder: it may start after the
151
+ review batch exists, including while the user is on filter choice, but template
152
+ review cannot start until the user answers filter choice and chooses Use
153
+ Template in Messages. AI Generated is an explicit opt-out that cancels or
154
+ ignores the background template draft. If the post-lead agents are absent, the
155
+ main thread still orchestrates the same branches from the compact context with
156
+ MCP tools/assets.
151
157
 
152
158
  Use rendered Markdown for user review surfaces, not fenced code blocks. Keep
153
159
  lines short, use indexed section labels and bullets, and translate internal
@@ -200,7 +206,7 @@ After every `update_campaign({ campaignId, currentStep })`, use
200
206
  `get_campaign_navigation_state` when available as a compact orientation check:
201
207
  match the saved campaign state to the expected watch-link step, explain the
202
208
  current state in one sentence, and only then continue. Sender selection belongs
203
- at Settings after message approval and 10-row validation. After message
209
+ at Settings after message approval and 15-row validation. After message
204
210
  validation, use Settings to help the user connect or select a LinkedIn sender.
205
211
  Explain Slack reply review before launch. After sender selection, attach the
206
212
  recommended sequence and move the watched UI to Send. Do not start the campaign
@@ -561,26 +567,31 @@ updates.
561
567
  Do not load the full long-form `generate-messages` subskill in this
562
568
  create-campaign path; if the safety gate cannot safely approve the draft,
563
569
  route to revise messaging with the concrete failure.
570
+ This compatibility path is not a generate-message fast mode.
564
571
  Do not synthesize `message-validation.md` from the brief, lead review, or
565
572
  general knowledge.
566
573
  5. Create the campaign shell early with the v1 brief so the user can open the
567
574
  watch link and see useful setup state immediately. Import only the first
568
575
  bounded review batch after the source is attached to the campaign; do not
569
- queue workflow cells, attach a sequence, or start until
570
- `message-validation.md` proves the message-review safety-gate workflow ran,
571
- `message-review.md` approves the template, rubrics are saved, and the
572
- approved message set is synced into the campaign brief.
576
+ queue workflow cells, attach a sequence, or start until the filter choice is
577
+ resolved, Messages has shown Use Template / AI Generated, template/token
578
+ rules are approved when Use Template is chosen, rubrics are saved when
579
+ filters are enabled, and the approved message set is synced into the campaign
580
+ brief. Product Generate Message cells must not run from the background
581
+ template path before that template/token approval.
573
582
  Do not ask the user to approve the brief before shell creation unless they
574
583
  explicitly requested a no-write draft; the shell itself is the review surface.
575
584
  6. The main thread owns watch navigation. Call
576
585
  `mcp__sellable__update_campaign({ campaignId, currentStep })` before major
577
586
  visible work so the user can watch progress in the app: `create-offer` for
578
587
  the brief, `pick-provider` or the selected provider step while sourcing,
579
- `filter-choice` after the 10-row review batch, `messages` or
580
- `auto-execute-messaging` for message work, `validate-sample` for validation,
581
- `awaiting-user-greenlight` for the final handoff, `settings` for sender
582
- selection, `sequence` after sender attach, and `send` once the recommended
583
- sequence is attached. Do not advance the step backward.
588
+ `filter-choice` after the 15-row review batch, `messages` for the Use
589
+ Template / AI Generated mode choice, `auto-execute-messaging` for approved
590
+ message work or the product's AI-generated path, `awaiting-user-greenlight`
591
+ for the final handoff, `settings` for sender selection, `sequence` after
592
+ sender attach, and `send` once the recommended sequence is attached.
593
+ `validate-sample` is recovery/legacy only if reached. Do not advance the
594
+ step backward.
584
595
  7. Keep `selectedLeadListId` as the source list and `workflowTableId` as the
585
596
  campaign table. Do not use disk files as the post-mint source of truth.
586
597
  8. Do not ask the user to run another command.
@@ -50,8 +50,10 @@ template, senderIds, sequence template, and running state.
50
50
  There is no separate approval-packet, commit-gate, or mint step in the active
51
51
  shell-first flow. The campaign exists early for watch mode. The hard boundary
52
52
  is import/enrichment: no leads are imported, no workflow cells are queued, no
53
- sequence is attached, and nothing starts until the source is selected, rubrics
54
- are saved, and the approved message set is synced into the campaign brief.
53
+ sequence is attached, and nothing starts until the source is selected, filter
54
+ choice is resolved, rubrics are saved when filters are enabled, and Messages
55
+ has either approved template/token rules or selected the product's AI-generated
56
+ path.
55
57
  </objective>
56
58
 
57
59
  <files>
@@ -96,8 +98,8 @@ Optional debug/UAT draft directory, disabled in normal customer runs:
96
98
  state. Use `create-offer` for the brief, `pick-provider` or the selected
97
99
  provider step while sourcing, `filter-choice` after the 15-row review batch is
98
100
  imported, `messages`/`auto-execute-messaging` for message work,
99
- `validate-sample` for the 15-row validation cascade, and
100
- `awaiting-user-greenlight` for Settings. Do not advance `currentStep` backward.
101
+ `awaiting-user-greenlight` for Settings, and `validate-sample` only for
102
+ recovery/legacy validation if reached. Do not advance `currentStep` backward.
101
103
  - After the shell is minted, normal resume paths read the CampaignOffer first.
102
104
  Use debug files to explain or reconstruct work, not to decide whether a
103
105
  post-mint gate is allowed. validation/debug artifacts are not durable campaign
@@ -442,11 +444,12 @@ brief`, `Revise target`, `Revise offer/proof`, and `Other / custom`.
442
444
  not given a specific source direction, use the default sequential source
443
445
  funnel:
444
446
  `Cool. I'm going to find people who are both a good fit and active enough to
445
- be worth a LinkedIn test. I'll start with warm LinkedIn post engagement because
446
- that gives the strongest message context if enough ICP-looking people are
447
- engaging. If that does not clear a quick viability check, I'll switch to Sales
448
- Nav with recent activity, then broader Sales Nav, and use Prospeo only as the
449
- fallback. No leads import until you approve the source.`
447
+ be worth a LinkedIn test. I'll start with people engaging with relevant LinkedIn
448
+ posts because that gives the strongest message context if enough ICP-looking
449
+ people are engaging. If that does not clear a quick viability check, I'll switch
450
+ to Sales Nav to find ICP people actively posting on LinkedIn, then search by
451
+ titles, and use Prospeo for a broader account/contact path. No leads import
452
+ until you approve the source.`
450
453
  The watched campaign should still be on Pick Provider while this source logic
451
454
  is being explained. If the default first lane is Signal Discovery, say clearly
452
455
  that Codex is about to test Signal Discovery as a viability path, not import
@@ -463,19 +466,23 @@ fallback. No leads import until you approve the source.`
463
466
  - explicit compare request -> compare only the requested sources
464
467
  - In watch mode, do not skip the Pick Provider checkpoint. First move the
465
468
  campaign to `pick-provider` and narrate the source-selection reasoning there.
466
- After that visible checkpoint, move the campaign to the first source lane that
467
- will actually be tested (`signal-discovery`, `sales-nav`, `prospeo`, or the
469
+ While the watched browser is still on Pick Provider, ask for approval before
470
+ starting Signal Discovery or a user-directed first lane. After that visible
471
+ checkpoint and approval, move the campaign to the first source lane that will
472
+ actually be tested (`signal-discovery`, `sales-nav`, `prospeo`, or the
468
473
  user-directed lane), then run the campaign-attached provider prompt + provider
469
474
  search in the parent thread with `campaignOfferId`, `confirmed: true`, and
470
- `currentStep` when the tool accepts it. If that lane fails the quick viability
471
- gate, update the campaign step and watchNarration before trying the next lane
472
- so the user sees the source switch happen in the app.
475
+ `currentStep` when the tool accepts it. If that lane has timeout/error, zero
476
+ raw results, weak ICP fit, or weak message context, update the campaign step
477
+ and watchNarration before trying the next approved lane or ask the user to
478
+ revise the source/target before import. All lanes failed is a terminal
479
+ revise-source state, not an import state.
473
480
  - After the lead sample/source decision is ready and approved,
474
481
  show the next progress line:
475
482
  `Lead source is set. I'll import the first 15-row review batch into the
476
- campaign table, then add fit filters and draft the first message from that same
477
- sample. You can inspect filters once they are saved, but enrichment and message
478
- checks wait until the message draft is ready and approved.`
483
+ campaign table, then ask you to Choose filters or skip. I may let the Message
484
+ Draft Builder prepare a template in the background, but template review waits
485
+ until the filter choice is resolved and you choose Use Template.`
479
486
  - During long post-intake work, show concise progress checkpoints before the
480
487
  next expensive stage: source being checked, source switch/tradeoff if any,
481
488
  lead sample usable, filter/message drafting, and message-review rule loading.
@@ -517,17 +524,19 @@ checks wait until the message draft is ready and approved.`
517
524
  candidate messages and element tests, but it cannot select the final winner
518
525
  and cannot override `lead-filter.md`.
519
526
  - `message-validation.md` is the internal validation artifact produced by the
520
- user-facing `message generation` stage.
527
+ Message Draft Builder / `message generation` stage. It is provisional until
528
+ the user answers filter choice and then chooses Use Template in Messages.
521
529
  - `message-review.md` and `message-review-decision.md` are the mandatory
522
530
  message quality gate outputs between `message-validation.md` and
523
531
  `approval-packet.md`.
524
532
  - Run the dependency chain as a DAG: `create-campaign-brief` -> `find leads` ->
525
533
  bounded import/confirm. Once the source decision, lead sample, and campaign
526
- table `workflowTableId` exist, the normal path is the
527
- `post-lead-workstreams` step. Launch `filter leads` and `message generation`
528
- from the same basis (live campaign brief, source decision, lead sample, and
529
- the imported review-batch rows) as separate workstreams when the host exposes
530
- the named Sellable post-find-leads agents or real background work.
534
+ table `workflowTableId` exist, the normal path is the `filter-choice` user
535
+ gate. If the user chooses filters, `post-lead-workstreams` launches filter
536
+ leads and can let the Message Draft Builder run from the same basis (live
537
+ campaign brief, source decision, lead sample, and the imported review-batch
538
+ rows) as separate workstreams when the host exposes the named Sellable
539
+ post-find-leads agents or real background work.
531
540
  First call `get_post_find_leads_scout_registry` and use the returned
532
541
  canonical `name` values only when those names are available in the current
533
542
  runtime. In Claude Code, use both returned Task/Agent subagents in the same
@@ -538,14 +547,19 @@ checks wait until the message draft is ready and approved.`
538
547
  context. Do not surface agent install status to the customer. The existing
539
548
  `filter-rubric` and `message-generation` steps remain focused retry and
540
549
  resume targets.
541
- - Message generation does not need `lead-filter.md` to start. The moment the
542
- bounded review batch is imported and `workflowTableId` is ready, start the
543
- message-generation workstream from the live campaign brief, source decision,
544
- lead sample, and the imported campaign table sample. It can prepare
545
- proof inventory, token strategy, and candidate angles while filter-leads
546
- tightens keep/exclude rules. Approval still waits for both `lead-filter.md`
547
- and `message-validation.md`, then reconciles that the selected message basis
548
- rows still pass the final filter.
550
+ - Message generation does not need `lead-filter.md` to start, but it is only
551
+ background template drafting until the user reaches Messages. The moment the
552
+ bounded review batch is imported, `workflowTableId` is ready, and the user is
553
+ on/after filter choice, the Message Draft Builder may start from the live
554
+ campaign brief, source decision, lead sample, and imported campaign table
555
+ sample. It can prepare proof inventory, token strategy, and candidate angles
556
+ while filter-leads tightens keep/exclude rules. Template review cannot start
557
+ until filter choice is answered and the user chooses Use Template. If filters
558
+ are enabled, template review is locked until rubrics are saved, a bounded
559
+ filter run has usable passing/probably passing rows, and the draft reconciles
560
+ to those rows. Prefer at least 2 usable passing rows; if only 1 passes, show
561
+ weak-sample copy and ask whether to continue, revise, import more, or skip
562
+ filters.
549
563
  If a legacy/resume host starts message prep from preview rows before import,
550
564
  it still needs at least 3 probable good-fit rows and must reconcile the final
551
565
  winner against the imported review batch before message review.
@@ -612,15 +626,29 @@ workstreams`, `in parallel`, or `background` unless parallel branches were
612
626
  batch`, and a no-launch safety note. Do not leave the guide saying
613
627
  `source approved` or `I'll show the review-batch outcome` once import is
614
628
  starting.
629
+ - After the bounded review batch is present, update the watched browser to
630
+ `currentStep: "filter-choice"` with `watchNarration.stage: "fit-message"` and
631
+ ask the user to Choose filters or skip. If import succeeds but row readback
632
+ returns zero rows, do not move to filter choice; keep the user in source/import
633
+ recovery and ask whether to retry import, import more from the approved
634
+ source, or revise source. Active filtering starts only after rubrics are
635
+ saved; do not say filtering the batch before rubrics are saved.
615
636
  - After Lead Fit Builder saves rubrics, move the watched browser to Filter
616
637
  Leads before waiting for message work to finish. Persist
617
638
  `enableICPFilters: true`, `currentStep: "apply-icp-rubric"`, and
618
639
  `watchNarration.stage: "fit-message"` so the user can see fit filtering
619
- happen while the first message sample finishes. After message approval,
620
- persist `useMessagingTemplate: true` and keep `enableICPFilters: true`;
621
- sample validation then runs the review-batch cascade, and the user should be
622
- walked through fit results, generated message results, and
623
- Settings/sender/sequence handoff.
640
+ happen while the Message Draft Builder finishes. The next user-facing Messages
641
+ screen must show mode choice first: Use Template and AI Generated. Use
642
+ Template is recommended. AI Generated is an explicit opt-out that cancels or
643
+ ignores the background template draft and must not let late template output
644
+ overwrite campaign state. Product Generate Message cells should not run from
645
+ the background template path until template/token rules are approved. After
646
+ message approval, update the campaign brief with an Approved Message Template
647
+ containing `{{...}}` tokens and keep `enableICPFilters: true`; Generate
648
+ Message detects template mode from those tokens, not from
649
+ `useMessagingTemplate`. Sample validation then runs the review-batch cascade,
650
+ and the user should be walked through fit results, generated message results,
651
+ and Settings/sender/sequence handoff.
624
652
  - During pre-import validation, do not call `check_rubric`; use the lead-filter
625
653
  artifacts and only use campaign-backed scoring after Step 13 imports the
626
654
  15-lead test batch.
@@ -666,7 +694,7 @@ batch`, and a no-launch safety note. Do not leave the guide saying
666
694
 
667
695
  <conditional_gates>
668
696
 
669
- There are four customer-visible gates in the net-new hosted flow:
697
+ There are six customer-visible gates in the net-new hosted flow:
670
698
 
671
699
  - `brief-review` asks whether to approve the rendered campaign brief before
672
700
  Find Leads starts. Do not skip this by inferring approval from setup
@@ -674,11 +702,17 @@ There are four customer-visible gates in the net-new hosted flow:
674
702
  - `lead-review` / source decision asks whether to approve the selected source
675
703
  path and sample before moving into filter/message work. Do not skip this by
676
704
  compressing the source decision into message review.
677
- - `message-review` is the mandatory pre-import message quality gate. It asks
678
- only whether to proceed with the selected message (`approve-message`) or run
679
- one more messaging revision (`revise-messaging`). `approve-message` authorizes
680
- syncing the approved message set into the campaign brief, saving rubrics,
681
- importing the bounded 15-lead test batch, and queueing/observing that sample.
705
+ - `filter-choice` asks whether to use filters or skip after the non-empty
706
+ review batch is imported. This is the first post-import user gate.
707
+ - `messages-mode-choice` asks whether to Use Template or choose AI Generated.
708
+ Use Template is recommended. AI Generated is an explicit opt-out that cancels
709
+ or ignores the background template draft.
710
+ - `message-review` is the mandatory template quality gate only when the user
711
+ chooses Use Template. It asks only whether to proceed with the selected
712
+ message (`approve-message`) or run one more messaging revision
713
+ (`revise-messaging`). `approve-message` authorizes syncing the approved
714
+ template/token rules into the campaign brief and queueing/observing the
715
+ review-batch cascade.
682
716
  - The sender/settings/sequence handoff is the launch gate. After message
683
717
  validation, use Settings to help the user connect or select a LinkedIn sender.
684
718
  Explain Slack reply review before launch. After sender selection, attach the
@@ -814,6 +848,12 @@ Required behavior:
814
848
  watched campaign moving, not to compare every plausible lane in parallel.
815
849
  Run only enough evidence for the current lane to pass or fail the quick gate,
816
850
  then stop on the first viable source unless the user asked to compare.
851
+ User-facing fallback copy should stay fifth-grade clear: people engaging with
852
+ relevant LinkedIn posts -> Sales Nav to find ICP people actively posting on
853
+ LinkedIn -> search by titles -> Prospeo for a broader account/contact path.
854
+ The older provider label `broader Sales Nav` maps to the plain-language
855
+ `search by titles` fallback; `Prospeo only as the fallback` maps to the
856
+ plain-language broader account/contact path. Keep user-facing copy simple.
817
857
  1. Start with LinkedIn Engagement / active LinkedIn posts (internal provider:
818
858
  Signals / `signal-discovery`) because recent engagement gives the strongest
819
859
  message context and expected reply-rate upside. Search intersection keyword
@@ -842,6 +882,10 @@ Required behavior:
842
882
  start with Signal Discovery. If they name titles/personas/company filters,
843
883
  start with Sales Nav. If they explicitly ask for a comparison, compare only
844
884
  those requested sources.
885
+ - failed or empty source lanes do not import leads. A timeout/error, zero raw
886
+ results, weak ICP fit, or weak message context must trigger the next approved
887
+ lane or a revision question before import. All lanes failed is a terminal
888
+ revise-source state, not an import state.
845
889
  - run source scouts in parallel only when the user explicitly requested a
846
890
  comparison, the current turn is resuming from already-started parallel scouts,
847
891
  or the first viable source is borderline and one cheap fallback check is
@@ -1237,29 +1281,49 @@ Do not:
1237
1281
 
1238
1282
  ## Step 3: Generate Message
1239
1283
 
1240
- Step 3 is orchestrated by the main thread and executed either by the
1241
- `post-find-leads-message-scout` worker or by the parent-thread fallback. The
1242
- worker carries the campaign-launch message rules in its agent prompt. The
1243
- parent-thread fallback must load the small safety-gate reference before writing
1244
- message artifacts:
1284
+ Step 3 is the Message Draft Builder path. It is orchestrated by the main thread
1285
+ and executed either by the `post-find-leads-message-scout` worker or by the
1286
+ parent-thread fallback. The worker carries the campaign-launch message rules in
1287
+ its agent prompt. The parent-thread fallback must load the small safety-gate
1288
+ reference before writing message artifacts:
1245
1289
 
1246
1290
  ```
1247
1291
  mcp__sellable__get_subskill_asset({ subskillName: "create-campaign-v2", assetPath: "references/message-review-safety-gate.md" })
1248
1292
  ```
1249
1293
 
1250
1294
  Do not load the full long-form `generate-messages` subskill in
1251
- `create-campaign-v2`. The safety-gate asset is a parent-thread fallback for hosts
1252
- that cannot launch `post-find-leads-message-scout`, not the preferred route. If
1253
- the safety gate is missing a needed campaign-specific rule or the draft fails
1254
- quality gates, stop at `revise-messaging` with the exact failure instead of
1255
- pulling the long prompt into the main thread.
1256
-
1257
- Do NOT proceed to Step 4 (message review gate) unless `message-validation.md`
1258
- contains the safety-gate required sections, a raw sendable Selected Winner, and an
1259
- explicit single-first-send PASS. If `message-validation.md` contains post-accept
1260
- DM, follow-up, second-touch, cadence, branch, or other sequence-shaped copy, do
1261
- not summarize it as ready; route back to message-generation and require a
1262
- single first outbound send.
1295
+ `create-campaign-v2`. The safety-gate asset is a parent-thread compatibility
1296
+ path for hosts that cannot launch `post-find-leads-message-scout`, not a
1297
+ generate-message fast-mode prompt and not the preferred route. If the safety gate
1298
+ is missing a needed campaign-specific rule or the draft fails quality gates, stop
1299
+ at `revise-messaging` with the exact failure instead of pulling the long prompt
1300
+ into the main thread.
1301
+
1302
+ Do NOT proceed to Step 4 (message review gate) unless the user has answered
1303
+ filter choice, the Messages step has shown the mode choice, the user chose Use
1304
+ Template, and `message-validation.md` contains the safety-gate required
1305
+ sections, a raw sendable Selected Winner, and an explicit single-first-send
1306
+ PASS. If the user reaches Messages and chose Use Template before the draft is
1307
+ ready, say you are waiting for the Message Draft Builder and do not ask for
1308
+ approval. If the draft worker fails, produces no usable message, or has no known
1309
+ worker status, require retry/regenerate copy instead of approval copy. If
1310
+ `message-validation.md` contains post-accept DM, follow-up, second-touch,
1311
+ cadence, branch, or other sequence-shaped copy, do not summarize it as ready;
1312
+ route back to message-generation and require a single first outbound send.
1313
+
1314
+ Messages first shows mode choice:
1315
+
1316
+ 1. Use Template (recommended): wait for and review the Message Draft Builder
1317
+ template. If filters are enabled, lock this review until saved rubrics and a
1318
+ bounded filter run produce usable passing/probably passing rows. Prefer at
1319
+ least 2 usable passing rows; if only 1 passes, use weak-sample copy and ask
1320
+ whether to continue, revise, import more, or skip filters.
1321
+ 2. AI Generated: this is an explicit opt-out. Cancel or ignore the background
1322
+ template draft and prevent late template output from overwriting campaign
1323
+ state.
1324
+
1325
+ Product Generate Message cells should not run from the background template path
1326
+ until template/token rules are approved.
1263
1327
 
1264
1328
  After the main-chat message approval, update_campaign_brief writes `## Approved
1265
1329
  Message Template` with `{{...}}` tokens before any Generate Message cascade is
@@ -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",
@@ -1001,6 +1015,18 @@
1001
1015
  "stripCarryData": true,
1002
1016
  "sampleSizeFromConfig": "sample.sampleSize (15)"
1003
1017
  },
1018
+ {
1019
+ "action": "require_non_empty_review_batch_before_filter_choice",
1020
+ "after": "get_rows_minimal",
1021
+ "blocksCurrentStep": "filter-choice",
1022
+ "onZeroRows": "source-import-recovery",
1023
+ "recoveryChoices": [
1024
+ "retry import",
1025
+ "import more from approved source",
1026
+ "revise source"
1027
+ ],
1028
+ "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."
1029
+ },
1004
1030
  {
1005
1031
  "tool": "update_campaign",
1006
1032
  "requiredFields": [
@@ -1013,7 +1039,7 @@
1013
1039
  "watchNarration.stage": "fit-message",
1014
1040
  "watchNarration.headline": "Added to Campaign"
1015
1041
  },
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."
1042
+ "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
1043
  }
1018
1044
  ],
1019
1045
  "allowedTools": [
@@ -1040,7 +1066,7 @@
1040
1066
  "watchRequired": true,
1041
1067
  "waitFor": "review_batch_imported",
1042
1068
  "transitions": {
1043
- "review_batch_imported": "post-lead-workstreams",
1069
+ "review_batch_imported": "filter-choice",
1044
1070
  "escalation_triggered": "escalation"
1045
1071
  },
1046
1072
  "requiredArtifacts": [
@@ -1054,6 +1080,65 @@
1054
1080
  "selectedLeadListId"
1055
1081
  ]
1056
1082
  },
1083
+ {
1084
+ "id": "filter-choice",
1085
+ "label": "Filter choice",
1086
+ "currentStepValue": "filter-choice",
1087
+ "normalFlow": true,
1088
+ "onEnter": [
1089
+ {
1090
+ "action": "show_filter_choice",
1091
+ "requiredVisibleContent": [
1092
+ "Choose filters or skip",
1093
+ "Use filters to keep only qualified leads",
1094
+ "Skip filters and continue to Messages",
1095
+ "active filtering starts only after rubrics are saved"
1096
+ ],
1097
+ "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."
1098
+ },
1099
+ {
1100
+ "tool": "update_campaign",
1101
+ "requiredValues": {
1102
+ "currentStep": "filter-choice",
1103
+ "watchNarration.stage": "fit-message"
1104
+ },
1105
+ "watchNarrationRule": "Show Added to Campaign with a Choose filters or skip decision. Do not say filtering the batch before rubrics are saved."
1106
+ }
1107
+ ],
1108
+ "allowedTools": [
1109
+ "AskUserQuestion",
1110
+ "request_user_input",
1111
+ "update_campaign",
1112
+ "get_campaign_navigation_state"
1113
+ ],
1114
+ "doNotAllow": [
1115
+ "create_campaign",
1116
+ "save_rubrics",
1117
+ "import_leads",
1118
+ "confirm_lead_list",
1119
+ "queue_cells",
1120
+ "start_campaign",
1121
+ "generate_messages",
1122
+ "enrich_with_prospeo",
1123
+ "bulk_enrich_with_prospeo"
1124
+ ],
1125
+ "watchRequired": true,
1126
+ "waitFor": [
1127
+ "filters_enabled",
1128
+ "filters_skipped",
1129
+ "revise_leads"
1130
+ ],
1131
+ "transitions": {
1132
+ "filters_enabled": "post-lead-workstreams",
1133
+ "filters_skipped": "messages-mode-choice",
1134
+ "revise_leads": "find-leads"
1135
+ },
1136
+ "interruptOnly": true,
1137
+ "requiredCampaignState": [
1138
+ "campaignId",
1139
+ "workflowTableId"
1140
+ ]
1141
+ },
1057
1142
  {
1058
1143
  "id": "post-lead-workstreams",
1059
1144
  "label": "Post-import filter and message workstreams",
@@ -1106,8 +1191,9 @@
1106
1191
  "ownership": "proof inventory, token strategy, angle drafting, skeptical-prospect review, and selected winner only"
1107
1192
  }
1108
1193
  ],
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.",
1194
+ "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 brief.md, lead-review.md, lead-sample.json, and the imported campaign table sample, including while the user is on filter choice. This background template draft is provisional speed work only. 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
1195
  "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.",
1196
+ "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
1197
  "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
1198
  "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
1199
  "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."
@@ -1161,6 +1247,22 @@
1161
1247
  "when": "after_save_rubrics_succeeds_before_waiting_for_message_validation",
1162
1248
  "writesCampaignState": "currentStep:apply-icp-rubric"
1163
1249
  },
1250
+ {
1251
+ "tool": "wait_for_rubric_results",
1252
+ "requiredValues": {
1253
+ "includeRows": false,
1254
+ "minPassedCount": 1
1255
+ },
1256
+ "purpose": "wait_for_bounded_filter_run_before_messages_mode",
1257
+ "readVia": "stats_only_tool_result",
1258
+ "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."
1259
+ },
1260
+ {
1261
+ "action": "require_usable_filtered_rows_before_messages_mode",
1262
+ "after": "wait_for_rubric_results",
1263
+ "requiredBeforeMessagesMode": true,
1264
+ "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."
1265
+ },
1164
1266
  {
1165
1267
  "tool": "get_campaign_navigation_state",
1166
1268
  "purpose": "confirm the watched UI moved to Filter Leads after rubrics saved",
@@ -1197,6 +1299,7 @@
1197
1299
  "get_subskill_asset",
1198
1300
  "get_post_find_leads_scout_registry",
1199
1301
  "save_rubrics",
1302
+ "wait_for_rubric_results",
1200
1303
  "update_campaign",
1201
1304
  "get_campaign_navigation_state",
1202
1305
  "Task",
@@ -1231,11 +1334,11 @@
1231
1334
  "confirm_with_user"
1232
1335
  ],
1233
1336
  "transitions": {
1234
- "post_lead_workstreams_ready": "message-review",
1337
+ "post_lead_workstreams_ready": "messages-mode-choice",
1235
1338
  "revise_leads": "find-leads",
1236
1339
  "revise_rubric": "filter-rubric",
1237
1340
  "revise_messaging": "message-generation",
1238
- "confirm_with_user": "message-review"
1341
+ "confirm_with_user": "messages-mode-choice"
1239
1342
  },
1240
1343
  "interruptOnly": true,
1241
1344
  "requiredCampaignState": [
@@ -1250,6 +1353,86 @@
1250
1353
  "message-candidate-drafts.md"
1251
1354
  ]
1252
1355
  },
1356
+ {
1357
+ "id": "messages-mode-choice",
1358
+ "label": "Messages mode choice",
1359
+ "currentStepValue": "messages",
1360
+ "normalFlow": true,
1361
+ "onEnter": [
1362
+ {
1363
+ "tool": "update_campaign",
1364
+ "requiredValues": {
1365
+ "currentStep": "messages",
1366
+ "watchNarration.stage": "review-ready"
1367
+ },
1368
+ "watchNarrationRule": "Messages first shows a mode choice: 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."
1369
+ },
1370
+ {
1371
+ "action": "show_messages_mode_choice",
1372
+ "choices": [
1373
+ "Use Template (recommended)",
1374
+ "AI Generated"
1375
+ ],
1376
+ "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."
1377
+ },
1378
+ {
1379
+ "action": "wait_for_message_draft_builder_when_use_template",
1380
+ "when": "user chose Use Template and draft is not ready",
1381
+ "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.",
1382
+ "forbiddenApprovalCopy": true
1383
+ },
1384
+ {
1385
+ "action": "handle_unusable_or_unknown_template_draft",
1386
+ "when": "draft worker fails, produces no usable message, or worker status is unknown",
1387
+ "requiredCopy": "retry or regenerate the template draft before approval",
1388
+ "forbiddenApprovalCopy": true
1389
+ },
1390
+ {
1391
+ "action": "cancel_or_ignore_background_template_on_ai_generated",
1392
+ "when": "user chose AI Generated",
1393
+ "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."
1394
+ },
1395
+ {
1396
+ "action": "route_ai_generated_to_product_path",
1397
+ "when": "user chose AI Generated",
1398
+ "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."
1399
+ }
1400
+ ],
1401
+ "allowedTools": [
1402
+ "AskUserQuestion",
1403
+ "request_user_input",
1404
+ "update_campaign",
1405
+ "get_campaign_navigation_state"
1406
+ ],
1407
+ "doNotAllow": [
1408
+ "create_campaign",
1409
+ "import_leads",
1410
+ "confirm_lead_list",
1411
+ "queue_cells",
1412
+ "start_campaign",
1413
+ "generate_messages",
1414
+ "enrich_with_prospeo",
1415
+ "bulk_enrich_with_prospeo"
1416
+ ],
1417
+ "watchRequired": true,
1418
+ "waitFor": [
1419
+ "use_template_ready",
1420
+ "use_template_waiting",
1421
+ "ai_generated_selected",
1422
+ "revise_messaging"
1423
+ ],
1424
+ "transitions": {
1425
+ "use_template_ready": "message-review",
1426
+ "use_template_waiting": "message-generation",
1427
+ "ai_generated_selected": "auto-execute-messaging",
1428
+ "revise_messaging": "message-generation"
1429
+ },
1430
+ "interruptOnly": true,
1431
+ "requiredCampaignState": [
1432
+ "campaignId",
1433
+ "workflowTableId"
1434
+ ]
1435
+ },
1253
1436
  {
1254
1437
  "id": "filter-rubric",
1255
1438
  "label": "Lead filters and production rubrics",
@@ -1408,7 +1591,7 @@
1408
1591
  "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
1592
  "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
1593
  "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."
1594
+ "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
1595
  ],
1413
1596
  "doNotAllow": [
1414
1597
  "create_campaign",
@@ -1583,12 +1766,11 @@
1583
1766
  "campaignId",
1584
1767
  "message-review-decision.md",
1585
1768
  "message-validation.md",
1586
- "lead-filter.md"
1769
+ "lead-filter.md when filters are enabled"
1587
1770
  ],
1588
- "when": "after_message_approved_before_import",
1771
+ "when": "after_message_approved_before_product_messaging",
1589
1772
  "fields": [
1590
- "campaignBrief with ## Approved Message Template, Token Fill Rules, Token Fill Examples",
1591
- "useMessagingTemplate:true"
1773
+ "campaignBrief with ## Approved Message Template containing {{...}} tokens, Token Fill Rules, Token Fill Examples"
1592
1774
  ],
1593
1775
  "requiredBeforeImport": false,
1594
1776
  "onFailure": "stop_before_import_or_enrichment",
@@ -1596,30 +1778,31 @@
1596
1778
  "writesCampaignState": "campaignBrief.Approved Message Template"
1597
1779
  },
1598
1780
  {
1599
- "action": "advance_watch_to_validation_after_message_approval",
1781
+ "action": "advance_watch_to_messaging_after_message_approval",
1600
1782
  "tool": "update_campaign",
1601
1783
  "requires": [
1602
1784
  "campaignId",
1603
1785
  "message-review-decision.md"
1604
1786
  ],
1605
1787
  "requiredValues": {
1606
- "currentStep": "validate-sample",
1788
+ "currentStep": "auto-execute-messaging",
1607
1789
  "enableICPFilters": true,
1608
- "useMessagingTemplate": true,
1609
1790
  "watchNarration.stage": "review-ready"
1610
1791
  },
1611
1792
  "when": "after_update_campaign_brief_succeeds",
1612
1793
  "requiredBeforeCascade": true,
1613
- "writesCampaignState": "currentStep:validate-sample"
1794
+ "writesCampaignState": "currentStep:auto-execute-messaging"
1614
1795
  }
1615
1796
  ],
1616
1797
  "requiredArtifacts": [
1617
1798
  "brief.md",
1618
1799
  "lead-review.md",
1619
1800
  "lead-sample.json",
1620
- "lead-filter.md",
1621
1801
  "message-validation.md"
1622
1802
  ],
1803
+ "optionalRequiredArtifacts": [
1804
+ "lead-filter.md"
1805
+ ],
1623
1806
  "producesArtifacts": [
1624
1807
  "message-review.md",
1625
1808
  "message-review-decision.md"
@@ -1647,14 +1830,13 @@
1647
1830
  "revise_messaging"
1648
1831
  ],
1649
1832
  "transitions": {
1650
- "message_approved": "validate-sample",
1833
+ "message_approved": "auto-execute-messaging",
1651
1834
  "revise_messaging": "message-generation"
1652
1835
  },
1653
1836
  "interruptOnly": true,
1654
1837
  "requiredCampaignState": [
1655
1838
  "campaignId",
1656
- "workflowTableId",
1657
- "leadScoringRubrics"
1839
+ "workflowTableId"
1658
1840
  ]
1659
1841
  },
1660
1842
  {
@@ -1933,8 +2115,7 @@
1933
2115
  "fields": [
1934
2116
  "campaignBrief",
1935
2117
  "leadSourceType",
1936
- "leadSourceProvider",
1937
- "useMessagingTemplate"
2118
+ "leadSourceProvider"
1938
2119
  ],
1939
2120
  "skipWhen": "create_campaign minted a new campaign with the final approved brief and currentStep already set"
1940
2121
  },
@@ -2025,6 +2206,9 @@
2025
2206
  "id": "validate-sample",
2026
2207
  "label": "Step 14: Validate 15-lead test batch",
2027
2208
  "currentStepValue": "validate-sample",
2209
+ "normalFlow": false,
2210
+ "resumeOnly": true,
2211
+ "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
2212
  "reference": "references/sample-validation-loop.md",
2029
2213
  "counter": {
2030
2214
  "name": "revisionRound",
@@ -2034,6 +2218,14 @@
2034
2218
  "capFromConfig": "sample.maxRevisionRounds"
2035
2219
  },
2036
2220
  "onEnter": [
2221
+ {
2222
+ "action": "resolve_messages_mode",
2223
+ "branches": {
2224
+ "use-template": "Use the approved template/token rules already synced into CampaignOffer.campaignBrief.",
2225
+ "ai-generated": "Use the explicit AI-generated product path and cancel or ignore any background template draft."
2226
+ },
2227
+ "rule": "AI Generated mode must not read, apply, or be overwritten by the background Message Draft Builder template."
2228
+ },
2037
2229
  {
2038
2230
  "action": "watch_mode_orient"
2039
2231
  },
@@ -2138,7 +2330,8 @@
2138
2330
  "first_passing_row_unblocks_generate_message_observation",
2139
2331
  "timeout_never_repeats_without_customer_handoff",
2140
2332
  "timeout_or_underfloor_sample_never_advances_to_settings",
2141
- "review_batch_cascade_waits_for_saved_rubrics_and_approved_template"
2333
+ "review_batch_cascade_waits_for_saved_rubrics_and_approved_template",
2334
+ "generate_message_cells_do_not_run_from_background_template_until_template_token_rules_approved"
2142
2335
  ],
2143
2336
  "watchRequired": true,
2144
2337
  "waitFor": [
@@ -2209,6 +2402,7 @@
2209
2402
  "action": "verify_campaign_brief_template_mode",
2210
2403
  "requiredSection": "Approved Message Template",
2211
2404
  "requiredPattern": "{{...}}",
2405
+ "skipWhen": "messageMode is ai-generated",
2212
2406
  "onFailure": "runtime_failure_before_messaging",
2213
2407
  "repairBoundary": "before_import_only",
2214
2408
  "purpose": "ensure Generate Message uses the approved template instead of full-generation mode"
@@ -2219,7 +2413,7 @@
2219
2413
  },
2220
2414
  {
2221
2415
  "tool": "queue_cells",
2222
- "cellSource": "pending_generate_message_cells_for_passing_rows",
2416
+ "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
2417
  "when": "any passing row has pending or empty Generate Message cell",
2224
2418
  "batchSize": 100
2225
2419
  },
@@ -2269,7 +2463,9 @@
2269
2463
  "opus_reserved_for_highest_value_subset",
2270
2464
  "proposed_token_never_persisted_in_rewrite",
2271
2465
  "generate_messages_must_re_cascade_on_newly_passed_rows",
2272
- "campaign_brief_must_contain_approved_message_template_tokens_before_generate_message_cascade"
2466
+ "campaign_brief_must_contain_approved_message_template_tokens_before_generate_message_cascade",
2467
+ "ai_generated_mode_uses_explicit_product_path_and_ignores_background_template_draft",
2468
+ "generate_message_cells_do_not_run_from_background_template_until_template_token_rules_approved"
2273
2469
  ],
2274
2470
  "watchRequired": true,
2275
2471
  "waitFor": [
@@ -3,17 +3,17 @@
3
3
  Use this reference for `create-campaign-v2` message review only in two cases:
4
4
  when these rules are embedded inside the `post-find-leads-message-scout` agent
5
5
  prompt, or when the host cannot launch that agent and the parent thread needs a
6
- compact fallback. It is the campaign-launch subset of `generate-messages`: enough
7
- to prove a truthful first-send message, rendered token examples, and an approval
8
- decision without loading the full long-form message-generation prompt into the
9
- main Claude/Codex thread.
6
+ self-contained safety gate. It is the campaign-launch subset of
7
+ `generate-messages`: enough to prove a truthful first-send message, rendered
8
+ token examples, and an approval decision without loading the full long-form
9
+ message-generation prompt into the main Claude/Codex thread.
10
10
 
11
11
  In a normal installed Claude/Codex session, the message scout owns these rules.
12
- The parent-thread asset is a compatibility fallback, not a shortcut. Do not load
13
- the full `generate-messages` subskill in this flow. If the safety gate is missing
14
- a needed campaign-specific rule or the draft fails quality gates, stop at
15
- `revise-messaging` with the exact missing rule/failure instead of pulling the
16
- long prompt into the main thread.
12
+ The parent-thread asset is a compatibility safety path, not a fast-mode prompt
13
+ or a shortcut. Do not load the full `generate-messages` subskill in this flow. If
14
+ the safety gate is missing a needed campaign-specific rule or the draft fails
15
+ quality gates, stop at `revise-messaging` with the exact missing rule/failure
16
+ instead of pulling the long prompt into the main thread.
17
17
 
18
18
  ## Required Workflow
19
19
 
@@ -71,6 +71,13 @@ the full framework.
71
71
  `[insert]`, `[generated]`, or any instruction for a later model to fill.
72
72
  - Optional row-specific personalization must be grounded in a row field or
73
73
  omitted entirely. Never use generic filler like "your work" or "your team."
74
+ - Engagement-source personalization is a special case, not the default opener.
75
+ Do not write `saw you {{engagement_context}} on {{post_context}}`, `saw you
76
+ reacted to`, `saw you engaging with`, or equivalent source-citation copy as a
77
+ default hook. Only refer to the prospect's engagement when the line is
78
+ self-aware and low-certainty, for example `not sure if this is too specific,
79
+ but the [topic] thread felt close enough to send`. Otherwise omit the
80
+ engagement signal and use role/company/problem context.
74
81
  - Subject lines should be short, buyer-relevant, and specific. Avoid
75
82
  `quick question`, `demo`, `founder call`, sender names, and generic `outbound`.
76
83
  - If the message is plausible but not ready to send, set
@@ -35,6 +35,7 @@ stage labels. The driver label comes from the watch URL mode (`mode=claude` or
35
35
  Apollo, or existing list.
36
36
  - During search iteration, say what you tried, what you are trying next, what
37
37
  sample you are checking, and why that helps this campaign.
38
+ - At filter choice, do not say filtering the batch before rubrics are saved.
38
39
  - Avoid internal terms: MCP, tool, currentStep, workflow table, scout, debug.
39
40
  - Do not invent time estimates.
40
41
 
@@ -81,7 +82,7 @@ Default source funnel:
81
82
  "stage": "find-leads",
82
83
  "headline": "Choosing the lead source",
83
84
  "visibleState": "The browser is on Pick Provider while Codex explains the source path before opening a provider lane.",
84
- "agentIntent": "Codex will start with Signal Discovery when warm LinkedIn engagement looks plausible, then switch to Sales Nav or Prospeo only if the quick viability math fails.",
85
+ "agentIntent": "Codex will start with people engaging with relevant LinkedIn posts when that looks plausible, then switch to Sales Nav to find ICP people actively posting on LinkedIn, then search by titles, and use Prospeo for a broader account/contact path. Sales Nav with recent activity remains the first LinkedIn fallback.",
85
86
  "nextAction": "Review source",
86
87
  "safety": "No leads import until you approve the source."
87
88
  }
@@ -193,8 +194,8 @@ After review batch import:
193
194
  "stage": "fit-message",
194
195
  "headline": "Added to Campaign",
195
196
  "visibleState": "The first review batch is in the campaign.",
196
- "agentIntent": "Codex is adding fit filters to keep every send qualified while drafting the first message in the background.",
197
- "nextAction": "Review fit rules and message",
197
+ "agentIntent": "Codex is asking you to Choose filters or skip. The Message Draft Builder may prepare a template in the background, but review waits until the filter path is settled.",
198
+ "nextAction": "Choose filters or skip",
198
199
  "safety": "Nothing enriches, validates, or sends until the message is ready and approved.",
199
200
  "workerStatuses": {
200
201
  "leadFitBuilder": "running",
@@ -204,8 +205,10 @@ After review batch import:
204
205
  ```
205
206
 
206
207
  Use this after the selected review rows are present and before filters are
207
- saved. This is add-filters intent, not active filtering. `enableICPFilters`
208
- only becomes true after active filter criteria are saved.
208
+ saved. This is add-filters intent, not active filtering. Tell the user to
209
+ Choose filters or skip, and do not say filtering the batch before rubrics are
210
+ saved. `enableICPFilters` only becomes true after active filter criteria are
211
+ saved.
209
212
 
210
213
  Fit + message:
211
214
 
@@ -228,14 +231,27 @@ Review ready:
228
231
  ```json
229
232
  {
230
233
  "stage": "review-ready",
231
- "headline": "Review fit and message",
232
- "visibleState": "The fit rules and message sample are ready.",
233
- "agentIntent": "Approve them or ask for changes in chat.",
234
+ "headline": "Choose message mode",
235
+ "visibleState": "The Messages step shows Use Template and AI Generated.",
236
+ "agentIntent": "Use Template is recommended. AI Generated is an explicit opt-out that cancels or ignores the background template draft.",
234
237
  "nextAction": "Validation",
235
238
  "safety": "Codex will only continue after you approve."
236
239
  }
237
240
  ```
238
241
 
242
+ Messages waiting for template:
243
+
244
+ ```json
245
+ {
246
+ "stage": "review-ready",
247
+ "headline": "Waiting for the template",
248
+ "visibleState": "Use Template is selected, but the Message Draft Builder is still finishing.",
249
+ "agentIntent": "Codex is waiting for the Message Draft Builder and will not ask for approval until the template can be reviewed.",
250
+ "nextAction": "Review template",
251
+ "safety": "Late template output must not overwrite campaign state if AI Generated was selected."
252
+ }
253
+ ```
254
+
239
255
  Blocked/recovering:
240
256
 
241
257
  ```json
@@ -1411,6 +1411,13 @@ about`, or `clearly relevant` are BLOCKED. Source-y phrases such as
1411
1411
  context instead: `not sure if this is relevant, but if [topic] is part
1412
1412
  of what you're testing...`, `this may be too specific, but [topic] felt
1413
1413
  close enough to send`, or a similarly natural line.
1414
+ - **Engagement reference is opt-in, not the default opener:** do not
1415
+ default to `{{first_name}}, saw you {{engagement_context}} on
1416
+ {{post_context}}`, `saw you reacted to...`, or equivalent retrieval-log
1417
+ copy. That reads like surveillance unless the line is self-aware about
1418
+ the weak inference and uses low-certainty language. If that sounds
1419
+ awkward, omit the engagement source and open from role, company, problem,
1420
+ or the approved offer.
1414
1421
  - **No internal-metric flex:** internal process details are not proof by
1415
1422
  default. Compute time, token/cache details, model names, number of
1416
1423
  agents, orchestration internals, or `~5 min of compute per message`
@@ -1764,6 +1771,11 @@ Rules:
1764
1771
  - `"Saw you around [topic]."`
1765
1772
  - `"Saw you engaging with [topic]."`
1766
1773
  - signal-led opener shape is a **special case**, not the default. Use it only when the archived motion truly depends on it and the line can stay natural. Follow Superpower's `"saw you were active around some [topic] stuff recently and figured this might actually be relevant"` shape only when it reads like a real human note rather than a retrieval flex.
1774
+ - tokenized engagement-source opener shape is BLOCKED by default:
1775
+ `{{first_name}}, saw you {{engagement_context}} on {{post_context}}` reads
1776
+ like surveillance unless the filled line is explicitly self-aware and
1777
+ low-certainty. Prefer `not sure if this is too specific, but the [topic]
1778
+ thread felt close enough to send` or omit the engagement reference entirely.
1767
1779
  - if no per-lead signal exists, a category-level opener is acceptable as a fallback, but the Findings section must flag: `"Category-level opener used because lead-sample.json carries no per-lead signal. Real sends should surface signals in lead-sample.json before using this template."`
1768
1780
  - this pushes the real fix upstream to find-leads, where the sample payload should include signals when they exist
1769
1781