@sellable/mcp 0.1.171 → 0.1.173

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.
@@ -120,9 +120,15 @@ blocker.
120
120
  Do not write `saw you {{engagement_context}} on {{post_context}}`, `saw you
121
121
  reacted to`, `saw you engaging with`, or equivalent source-citation copy as a
122
122
  default hook. Only refer to engagement when the line is self-aware and
123
- low-certainty, for example: `not sure if this is too specific, but the
124
- [topic] thread felt close enough to send`. Otherwise omit the engagement
125
- signal and use role/company/problem context.
123
+ low-certainty, for example: `you might not remember the thread, but I found
124
+ you through a [topic] discussion and your [observable role/company context]
125
+ looked close to [problem]`. Otherwise omit the engagement signal and use
126
+ role/company/problem context.
127
+ - Do not describe the sender in third person inside the outbound message.
128
+ Lines like `p.s. Saju's angle is...`, `Christian's angle is...`, or
129
+ `[sender]'s approach is...` are internal notes leaking into copy. If the point
130
+ matters, write it in the sender's voice: `p.s. we usually pair the build with
131
+ enablement`, or omit it.
126
132
  - The selected winner is one first outbound send only. No post-accept DM,
127
133
  follow-up, cadence branch, sequence copy, or launch copy.
128
134
 
@@ -138,8 +138,8 @@ export async function getAuthStatus() {
138
138
  "5) Call `mcp__sellable__wait_for_cli_login({ sessionId })` using the sessionId returned by start_cli_login. " +
139
139
  "6) If the result is `error.type === 'tool_timeout_guard'`, IMMEDIATELY re-call wait_for_cli_login with the SAME sessionId — do not narrate, do not call start_cli_login again. Loop until you get a different result. " +
140
140
  "7) On `ok: true`, the user is signed in and `~/.sellable/config.json` has been written. Branch on `isReturningUser`: " +
141
- "if true, say `You're in — {activeWorkspaceName} workspace, ready to roll.\\n\\nNow paste the LinkedIn profile or company website for the client/company this campaign is for. I’ll use that to resolve the campaign identity before we pick the target, offer, proof, and lead source.\\n\\ne.g. https://example.com or https://www.linkedin.com/in/client-handle`; " +
142
- "if false, say `You're set up — your {activeWorkspaceName} workspace is ready.\\n\\nNow paste the LinkedIn profile or company website for the client/company this campaign is for. I’ll use that to resolve the campaign identity before we pick the target, offer, proof, and lead source.\\n\\ne.g. https://example.com or https://www.linkedin.com/in/client-handle`";
141
+ "if true, say `You're in.\\n\\nWhat is your LinkedIn profile URL?`; " +
142
+ "if false, say `You're set up.\\n\\nWhat is your LinkedIn profile URL?`";
143
143
  if (error instanceof SellableApiError && error.isAuthError) {
144
144
  return {
145
145
  ...base,
@@ -270,7 +270,7 @@ export async function bootstrapCreateCampaign(input = {}) {
270
270
  ? resumeDetected
271
271
  ? `Bootstrap complete.${workspaceNotice} Resume from campaign state and navigation diagnostics first; treat local draft artifacts as debug-only evidence. Then load ${createCampaignSubskill?.name ?? "create-campaign"} instructions with get_subskill_prompt({ subskillName: "${createCampaignSubskill?.name ?? "create-campaign"}" }); if the response has hasMore=true, continue with nextOffset until hasMore=false.`
272
272
  : flowVersion === "v2"
273
- ? `Bootstrap complete.${workspaceNotice} Load the compact create-campaign-v2 entry prompt once with get_subskill_prompt({ subskillName: "create-campaign-v2" }); load flow/reference assets lazily only when that stage needs them. Preserve the pre-intake sequence: confirm auth/workspace status, ask for the LinkedIn profile URL first with company website as fallback, run lightweight profile/company lookup, and ask whether the user has a current offer or wants the researched recommendation. Do not call list_senders or sender discovery during setup; sender availability belongs only to Settings after message approval. Then run the short setup/intake, write the campaign brief, call create_campaign once to mint the watchable shell, surface the returned watch link, and hand off to lead finding.`
273
+ ? `Bootstrap complete.${workspaceNotice} Load the compact create-campaign-v2 entry prompt once with get_subskill_prompt({ subskillName: "create-campaign-v2" }); load flow/reference assets lazily only when that stage needs them. Preserve the pre-intake sequence: confirm auth/workspace status, ask only for the LinkedIn profile URL, require that URL before continuing, run lightweight profile/company lookup, then ask the target, offer, credibility, and prospect-source setup questions. Do not call list_senders or sender discovery during setup; sender availability belongs only to Settings after message approval. Then write the campaign brief, call create_campaign once to mint the watchable shell, surface the returned watch link, and hand off to lead finding.`
274
274
  : `Bootstrap complete.${workspaceNotice} Load ${createCampaignSubskill?.name ?? "create-campaign"} instructions with get_subskill_prompt({ subskillName: "${createCampaignSubskill?.name ?? "create-campaign"}" }); if the response has hasMore=true, continue with nextOffset until hasMore=false. Follow that flow before calling create_campaign.`
275
275
  : "Bootstrap incomplete. Resolve blockingErrors and rerun bootstrap_create_campaign before provider/search/import tools.";
276
276
  // Strip prompt body from createCampaignSubskill — it's loaded via the host
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.171",
3
+ "version": "0.1.173",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -451,48 +451,44 @@ explicit client prospect identity in the invocation, do one lightweight lookup
451
451
  first:
452
452
 
453
453
  - LinkedIn profile: call `mcp__sellable__fetch_linkedin_profile`.
454
- - Website/domain/company: call `mcp__sellable__fetch_company` when possible,
455
- otherwise one web lookup.
454
+ - Non-profile URLs or company-page inputs are not enough to start this flow; ask
455
+ again for the person's LinkedIn profile URL.
456
456
  - Existing client prospect id: use it directly and do one company/profile lookup
457
- only if a URL/domain is also available.
457
+ only if a LinkedIn profile URL is also available.
458
458
 
459
459
  Then summarize what you found in one or two lines and ask the user to confirm
460
- the current company/focus before continuing, especially if public website data
461
- may be stale. Do not mention connected sender availability in this confirmation.
460
+ the current company/focus before continuing. Do not mention connected sender
461
+ availability in this confirmation.
462
462
 
463
463
  If the user did not provide the launch identity, ask in normal chat for the
464
- LinkedIn profile URL first, with the company website as the fallback. Do not ask
465
- them to choose an input type with the structured question tool:
464
+ LinkedIn profile URL. Do not ask them to choose an input type with the structured
465
+ question tool:
466
466
 
467
467
  ```text
468
- I’m ready to build this in {workspace}.
469
-
470
- What is your LinkedIn profile URL? If you do not have it handy, send your
471
- company website instead. I’ll research the person and company from that, then
472
- ask you to correct anything stale before we pick the target, offer, proof, and
473
- lead source.
468
+ What is your LinkedIn profile URL?
474
469
  ```
475
470
 
476
- After the user pastes a URL/domain, do the lightweight lookup. For a LinkedIn
477
- profile, call `mcp__sellable__fetch_linkedin_profile` and infer the current or
478
- most recent company from the profile. For a company website, call
479
- `mcp__sellable__fetch_company` when possible, otherwise one web lookup. If a
480
- LinkedIn profile URL is available, retain it as `senderLinkedinUrl` for
481
- `create_campaign`; if a `clientProspectId` is available, pass that instead.
471
+ After the user pastes a LinkedIn profile URL, call
472
+ `mcp__sellable__fetch_linkedin_profile` and infer the current or most recent
473
+ company from the profile. If they paste a non-profile URL or company page
474
+ instead, ask again for the person's LinkedIn profile URL. Retain the profile URL as
475
+ `senderLinkedinUrl` for `create_campaign`; if a `clientProspectId` is available,
476
+ pass that instead.
482
477
 
483
- After the user confirms the company/focus, run one lightweight company lookup
484
- if it has not already run, then ask an offer-readiness question before inferred
485
- strategy hardens:
478
+ After the user confirms the company/focus, ask the full setup intake before
479
+ inferred strategy hardens:
486
480
 
487
481
  ```text
488
- Do you already know the offer for this campaign, should I use the researched
489
- recommendation, or should we shape the offer together? If the website is stale,
490
- tell me what is current before I build the brief.
482
+ Who should we target first?
483
+ What offer should this campaign lead with?
484
+ What is the strongest credibility signal we can lead with?
485
+ How should we find prospects: find prospects for me, use a CSV of LinkedIn
486
+ profiles, or use a CSV of company domains?
491
487
  ```
492
488
 
493
489
  The setup questions should use the confirmed company context so they do not feel
494
- generic. When you present a recommendation, introduce it as based on the
495
- research you just did and keep it editable.
490
+ generic. When you present a researched recommendation, introduce it as based on
491
+ the research you just did and keep it editable.
496
492
 
497
493
  ### Sufficient Intake Bypass
498
494
 
@@ -520,9 +516,9 @@ If the invocation or any later user message explicitly asks for "yolo mode",
520
516
  me", "use best estimates", or "just run it", enable YOLO mode for the rest of
521
517
  the run. Treat YOLO as `interactionMode: "autonomous"` plus an intake policy:
522
518
 
523
- - If the campaign subject is missing, ask only for the LinkedIn profile URL
524
- first, with company website as the fallback, in normal chat; do not ask buyer,
525
- offer, proof, source, or filter setup questions before that.
519
+ - If the campaign subject is missing, ask only for the LinkedIn profile URL in
520
+ normal chat; do not continue from a non-profile URL and do not ask buyer, offer,
521
+ proof, source, or filter setup questions before the LinkedIn URL.
526
522
  - Treat any freeform directions already provided, or added later by the user, as
527
523
  operator directions for the rest of the run. If directions conflict, the newest
528
524
  user direction wins.
@@ -681,9 +677,7 @@ updates.
681
677
  ```text
682
678
  You're in — {activeWorkspaceName} workspace, ready to roll.
683
679
 
684
- Now — what is your LinkedIn profile URL? If you do not have it handy, send your company website instead. I’ll research the person and company from that, then ask you to correct anything stale before we pick the target, offer, proof, and lead source.
685
-
686
- e.g. https://www.linkedin.com/in/client-handle or https://example.com
680
+ What is your LinkedIn profile URL?
687
681
  ```
688
682
 
689
683
  - If `isReturningUser === false`, prepend ONE line confirming the new
@@ -692,17 +686,14 @@ updates.
692
686
  ```text
693
687
  You're set up — your {activeWorkspaceName} workspace is ready.
694
688
 
695
- Now — what is your LinkedIn profile URL? If you do not have it handy, send your company website instead. I’ll research the person and company from that, then ask you to correct anything stale before we pick the target, offer, proof, and lead source.
696
-
697
- e.g. https://www.linkedin.com/in/client-handle or https://example.com
689
+ What is your LinkedIn profile URL?
698
690
  ```
699
691
 
700
692
  No other lines. No "all set", no "signed in", no other acknowledgement.
701
693
 
702
- After the user pastes the URL, proceed with the identity-first campaign
703
- setup in the v2 subskill prompt. Resolve a LinkedIn profile with
704
- `fetch_linkedin_profile`, a company website/domain with `fetch_company`
705
- when possible, and mark the client/company research gate with
694
+ After the user pastes the LinkedIn profile URL, proceed with the
695
+ identity-first campaign setup in the v2 subskill prompt. Resolve it with
696
+ `fetch_linkedin_profile` and mark the client/company research gate with
706
697
  `complete_sender_research` when that protocol is required.
707
698
 
708
699
  3. If auth is not OK with `error.type === "workspace"` (token valid, no active
@@ -39,43 +39,43 @@ unless the user asks for debug output.
39
39
  4. Create the watchable campaign shell with `create_campaign` and the v1 brief.
40
40
  5. Surface the direct watch link.
41
41
  6. Choose and approve the lead source.
42
- 7. Materialize the approved source list and confirm/copy it into the campaign.
43
- Internally use the first 15 imported campaign-table rows as the initial
44
- execution slice for filter/message setup; do not present that as source
45
- sampling.
42
+ 7. Materialize the approved source list and confirm 15 campaign-table rows for
43
+ filter/message setup; do not present that as source sampling.
46
44
  8. Ask whether to use filters or skip them.
47
45
  9. Persist lead rubrics when filters are enabled, then ask approval while the
48
46
  app remains on Filter Rules.
49
47
  10. Move to Filter Leads only after saved filters are approved.
50
48
  11. Review and approve/revise the message template.
51
- 12. Sync the approved template into the brief, then queue bounded
52
- enrichment/filtering.
53
- 13. Move to Messages after one row passes and one generated message is ready;
54
- review it, then hand off to Settings, sender, sequence, and launch.
55
-
56
- There is no normal approval-packet, commit-gate, atomic-mint, or local
57
- artifact-validation step. Those belong only to legacy validation/rehearsal
58
- flows and the separate `create-campaign-v2-validation` subskill.
49
+ 12. Sync the approved template into the brief, then queue bounded filtering.
50
+ 13. After one row passes with a generated message, review it, then hand off to
51
+ Settings, sender, sequence, and launch.
59
52
 
60
53
  ## Identity-First Campaign Setup
61
54
 
62
- Do not treat the active Sellable workspace as the campaign subject. Resolve the
63
- client/company first, confirm whether the user already has a current offer, then
64
- draft the buyer, offer, proof, and source plan.
55
+ Do not treat the active workspace as the campaign subject. Resolve the
56
+ client/company, then confirm target, offer, trust proof, and prospect source
57
+ before drafting the brief.
65
58
 
66
59
  First visible request when no identity is known:
67
60
 
68
61
  ```text
69
- What is your LinkedIn profile URL? If you do not have it handy, send your company website instead.
62
+ What is your LinkedIn profile URL?
70
63
  ```
71
64
 
72
- After the user pastes a URL/domain, retain it as `senderLinkedinUrl` or the
73
- resolved `clientProspectId` input for `create_campaign`. Use one lightweight
74
- profile/company lookup before strategy questions, then say that public research
75
- may be stale and invite the user to correct it. Ask whether they know the offer,
76
- want Sellable's researched recommendation, or want to shape one together before
77
- buyer/offer/proof hardens. If multiple product lines or offers are plausible,
78
- ask one campaign-focus choice before the brief.
65
+ Require a LinkedIn profile URL before setup continues. If the user provides
66
+ anything else, ask again for the person's LinkedIn profile URL. Retain it as
67
+ `senderLinkedinUrl` or resolve `clientProspectId` for `create_campaign`. Run one
68
+ lightweight profile/company lookup before strategy questions, then say public
69
+ research may be stale and invite corrections.
70
+
71
+ Restore the full setup intake before the brief. Ask bounded choices for:
72
+
73
+ - target: "Who should we target first?" with the researched recommendation
74
+ - offer: "What offer should this campaign lead with?" with Sellable's
75
+ recommendation editable
76
+ - trust proof: "What is the strongest credibility signal we can lead with?"
77
+ - prospect source: "How should we find prospects?" with "Find prospects for me",
78
+ "Use a CSV of LinkedIn profiles", and "Use a CSV of company domains"
79
79
 
80
80
  Do not call `list_senders`, infer the campaign from connected senders, or show
81
81
  a sender picker during setup. Sender availability belongs only
@@ -109,8 +109,8 @@ real examples after we find and filter leads."
109
109
 
110
110
  Enable YOLO mode when the user asks for yolo/autopilot, passes `--yolo` or
111
111
  `mode=yolo`, or says to use best guesses/estimates and answer for them. Ask only
112
- for the LinkedIn profile URL first, with company website as the fallback, if the
113
- client/company is missing. After the lookup, infer buyer, offer/CTA, proof,
112
+ for the LinkedIn profile URL if the client/company is missing; do not continue
113
+ from a website or domain. After the lookup, infer buyer, offer/CTA, proof,
114
114
  source, filters, and message direction from company evidence plus user
115
115
  directions; newest directions win.
116
116
  Set `interactionMode: "autonomous"` once `campaignId` exists. Auto-select
@@ -123,7 +123,7 @@ launch. Never call `start_campaign` without explicit launch confirmation.
123
123
  Use the host-native structured question gate (`request_user_input` or
124
124
  AskUserQuestion) only for bounded choices:
125
125
 
126
- - campaign focus when the identity has multiple plausible offers
126
+ - target, offer, credibility, and prospect-source setup choices after research
127
127
  - source approval or source revision
128
128
  - use filters vs skip filters
129
129
  - approve message vs revise message
@@ -159,9 +159,8 @@ lead sourcing or anything can send.
159
159
  Good identity setup:
160
160
 
161
161
  ```text
162
- I’ll ask for the LinkedIn profile URL first, with the company website as a
163
- fallback. Then I’ll show the researched recommendation and you can correct
164
- anything stale before we pick the target, offer, proof, and lead source.
162
+ I’ll ask for the LinkedIn profile URL first. Then we’ll confirm who to target,
163
+ what to offer, what proof to lead with, and how to find prospects.
165
164
  ```
166
165
 
167
166
  Bad:
@@ -180,8 +179,8 @@ Better:
180
179
 
181
180
  ```text
182
181
  I found Christian Reyes connected here. Is that you, and is this campaign for
183
- Sellable? If not, choose LinkedIn profile or company domain and I’ll ask you to
184
- paste it in chat.
182
+ Sellable? If not, send the LinkedIn profile URL for the person this campaign is
183
+ for.
185
184
  ```
186
185
 
187
186
  Bad:
@@ -1 +1 @@
1
- {"version":"v2.1-compact","workflow":"create-campaign-v2","principle":"CampaignOffer state and watch link are canonical. Create the watched shell, approve source, materialize and confirm the source list, internally process the first campaign-table execution slice, save rubrics for approval, approve the message template, then run the bounded filter/message cascade before Settings, sequence, and explicit start.","normalCustomerPath":"Use campaign state, MCP responses, and concise watchNarration. Do not create, read, link, or surface local draft files.","legacyCompatibility":{"validationSubskill":"create-campaign-v2-validation","tailSubskill":"create-campaign-v2-tail","rule":"Legacy validation/rehearsal files are opt-in diagnostics only and are not active flow gates."},"commitGateChoices":["approve","revise-brief","revise-leads","revise-rubric","revise-messaging","abort"],"canonicalStateFields":["campaignId","watchUrl","campaignBrief","currentStep","watchNarration","interactionMode","providerSearchAssociation","selectedLeadListId","workflowTableId","filterChoice","leadScoringRubrics","messageDraftRecommendation","approvedMessageTemplate","senderIds","sequenceTemplate","runningState"],"watchNarrationTransitionContract":{"rule":"Every watched currentStep switch must include fresh watchNarration.","requiredFields":["stage","headline","visibleState","agentIntent","nextAction"],"copyMustInclude":["what just happened","current visible page/state","next user action"],"appliesToTools":["create_campaign","update_campaign","attach_recommended_sequence","start_campaign"]},"lazyReferences":{"watch":["references/watch-link-handoff.md","references/watch-guide-narration.md"],"source":["references/lead-validation-preview.md","references/step-13-import-leads.md"],"filter":["references/filter-leads.md"],"message":[],"tail":["references/sample-validation-loop.md","references/step-15-re-cascade.md","references/final-handoff-contract.md"]},"safetyBoundaries":["Do not call list_senders before Settings after message approval.","Do not import leads until the source decision is approved.","Do not queue cells until confirmed source rows exist in the campaign and the message/filter gates are satisfied.","Do not call start_campaign until the user explicitly confirms launch.","Do not use local files as durable state in normal customer runs."],"yoloMode":{"triggerPhrases":["yolo","--yolo","mode=yolo","autopilot","use best guesses","use best estimates","answer for me","just run it"],"identityRequestOnlyWhenMissing":true,"operatorDirectionsRule":"Treat freeform directions supplied at invocation or later as durable operator directions; newest conflicting direction wins.","setInteractionModeAfterCampaignCreate":"autonomous","autoSelectsPreLaunchChoices":["campaign focus","brief approval","source plan","source review/import approval","filters vs skip filters","filter rubric approval","message template approval when recommendation is approve-message","generated message review when quality floor passes","sender selection when exactly one connected sender is safe"],"mustPauseFor":["missing LinkedIn profile or company website","missing credentials or required data","ambiguous choice with no reasonable estimate","source/message/filter quality floor failure","final live launch confirmation"],"neverAutoStart":true},"steps":[{"id":"bootstrap","label":"Bootstrap","onEnter":[{"tool":"bootstrap_create_campaign","requiredValues":{"flowVersion":"v2"}},{"tool":"get_subskill_prompt","requiredValues":{"subskillName":"create-campaign-v2"},"purpose":"load the compact entry prompt once"}],"allowedTools":["bootstrap_create_campaign","get_auth_status","get_active_workspace","get_subskill_prompt","AskUserQuestion","request_user_input"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","update_campaign","queue_cells","start_campaign"],"waitFor":"bootstrap_complete","transitions":{"bootstrap_complete":"brief-interview"}},{"id":"brief-interview","label":"Client, offer, research, and brief","onEnter":[{"action":"resolve_campaign_identity_before_strategy_packet","allowedTools":["fetch_company","fetch_linkedin_profile","WebFetch","WebSearch"],"mustNotInferFromNameOnly":true,"doNotPresentSenderPickerBeforeIdentityInference":true,"fallback":"Ask for the LinkedIn profile URL first; use the company website as the fallback before strategy questions."},{"action":"run_campaign_identity_research_before_strategy_packet","target":"research-sender","requiredCompletion":"complete_sender_research","allowedTools":["get_subskill_prompt","fetch_linkedin_profile","fetch_company","fetch_linkedin_posts","fetch_company_posts","WebFetch","WebSearch","complete_sender_research"]},{"action":"ask_campaign_focus_only_when_ambiguous","uses":"request_user_input","singleChoice":true,"requiredOption":"Other / custom","neverCollectOpenTextWithStructuredQuestion":true,"skipIf":"yolo_mode with any reasonable best-estimate focus"},{"action":"confirm_current_offer_before_strategy_packet","uses":"request_user_input","question":"Do you already know the offer for this campaign?","options":["Use my current offer","Use Sellable's researched recommendation","Shape the offer together"],"copyMustInclude":["research basis","public website or LinkedIn may be stale","recommendation is editable"],"skipIf":"user already supplied a clear current offer or yolo_mode with any reasonable researched recommendation"},{"action":"infer_strategy_packet_in_yolo_mode","when":"yolo_mode","skipStructuredSetupQuestions":true,"inferFields":["buyer segment","offer/CTA","proof to use or avoid","lead source","filter choice","message direction"],"sourceOfTruth":"identity/company lookup plus operator directions","mustStateAssumptionsInBrief":true},{"action":"create_watchable_campaign_shell_with_v1_brief","tool":"create_campaign","requiredFields":["name","campaignBrief","clientProspectId or senderLinkedinUrl","currentStep","watchNarration"],"requiredValues":{"currentStep":"create-offer","watchNarration.stage":"brief"},"capture":["campaignId","watchUrl"],"canonicalStateWrites":["campaignId","watchUrl","campaignBrief","currentStep:create-offer"]},{"action":"surface_campaign_shell_watch_link","watchUrlSource":"create_campaign.watchUrl","requiredWatchUrlShape":"direct /campaign-builder/{campaignId}?mode={claude|codex} watch URL with token auto-login and workspace routing","copyMustInclude":["We'll keep building the campaign in this chat.","You can watch it come together in real time here:","I'll ask for your approval whenever I need your expertise or taste before moving forward.","Send changes here in chat."],"immediateNextMainChatLine":"Next, we'll choose where to find buyers. I won't add anyone yet.","codexBrowserHandoff":{"openWhenAvailable":false,"printWatchLinkOnly":true,"tellUserCommandEnterOrClick":false,"mustNotUseBrowserAutomation":true,"fallbackMustNotClaimInspection":true}}],"allowedTools":["get_subskill_prompt","fetch_company","fetch_company_posts","fetch_linkedin_profile","fetch_linkedin_posts","complete_sender_research","create_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign"],"waitFor":["campaign_shell_created","brief_ready","confirm_with_user"],"transitions":{"campaign_shell_created":"brief-review","brief_ready":"brief-review","confirm_with_user":"brief-review"}},{"id":"brief-review","label":"Brief review","onEnter":[{"action":"render_brief_inline","minimumVisibleDetail":"campaign direction, buyer, offer, proof, source plan, safety gates","copyMustInclude":["compact provenance labels: [from you], [from LinkedIn], [from website], [from case study], or [Sellable recommendation]","This is based on what I found. If your site or LinkedIn is stale, tell me what to update before I build the lead list.","Do you agree with this researched campaign direction?"],"copyMustNotInclude":["quoted first-message copy","Message Angle as final proof"],"messageHintRule":"If any message-shape hint remains, keep it as non-final bullets and say real examples come after leads are found and filtered."},{"action":"ask_brief_choice","uses":"request_user_input","choices":["Approve brief","Revise brief","Pause here"],"skipIf":"yolo_mode; auto_continue after rendering assumptions unless brief quality floor fails"}],"requiredCampaignState":["campaignId","watchUrl","campaignBrief","currentStep"],"allowedTools":["AskUserQuestion","request_user_input","update_campaign"],"doNotAllow":["create_campaign","list_senders","import_leads","confirm_lead_list","queue_cells","start_campaign"],"waitFor":["user_brief_confirmed","revise_brief","auto_continue"],"transitions":{"user_brief_confirmed":"find-leads","revise_brief":"brief-interview","auto_continue":"find-leads"}},{"id":"find-leads","label":"Find leads","sourceSelectionFunnel":{"preScoutRecommendationGate":{"required":true,"label":"Find buyers plan approval","mustHappenBefore":["get_provider_prompt","search_signals","search_sales_nav","search_prospeo","fetch_post_engagers","source-scout dispatch"],"show":["buyer groups or places we could check","best place to start","why the right buyers are likely to be there","what signs the next search will check","where to look next if the first place is too thin","what approval authorizes"],"approvalAuthorizes":"looking for the best places to find buyers; no one added yet","explanationMustInclude":["where the right buyers are already talking","why that place fits this campaign","enough likely prospects","what counts as a good sign","where to look next if thin","I won't add anyone yet","choose where to find buyers"],"yoloMode":{"autoApproveRecommendedLane":true,"mustShowAssumedChoice":true,"pauseIfConfidenceLow":true},"customerLanguage":{"readability":"grade-5","requiredHeading":"Find Buyers Plan","prefer":["place to look","best place to start","people to check","prospects","I won't add anyone yet"],"avoid":["lane","source scouting","provider","precision/scale tradeoff","evidence quality","pilot volume","ICP","workflow pain","lead-source scouting","not importing leads"],"example":"Brief approved. Next, we'll choose where to find buyers. I won't add anyone yet. I recommend starting with people already talking on LinkedIn about [plain topic]. That should help us find people who already care about [plain problem]. If this is too thin, I'll try [plain fallback] next.","termRule":{"buyers":"target market","peopleToCheck":"raw reactions/comments before fit is known","prospects":"likely usable people after fit","leads":"campaign rows"}}},"defaultWhenSourceUnspecified":["signal-discovery","sales-nav-recent-active","sales-nav-general","prospeo"],"userFacingFallbackOrder":["LinkedIn posts where the right buyers are already talking","people with the right titles who recently posted on LinkedIn","people with the right titles from a broader LinkedIn search","a broader company and contact search"],"parallelAllowedOnlyWhen":["user explicitly requested source comparison","resuming already-started parallel scouts","first viable source is borderline and one cheap fallback check is needed"]},"onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"pick-provider","watchNarration.stage":"find-leads","watchNarration.headline":"Review where to find buyers","watchNarration.visibleState":"The app is showing source selection before lead finding starts.","watchNarration.agentIntent":"Codex is explaining where it recommends looking first and where it will look next if that is too thin.","watchNarration.nextAction":"Approve where to look first or choose another place","watchNarration.safety":"Only deciding where to look. No one is added yet."},"purpose":"show the visible source-plan approval checkpoint before provider lanes"},{"tool":"get_source_scout_registry","purpose":"load canonical source scout names before optional branch launch"},{"action":"show_pre_scout_source_recommendation","uses":"request_user_input","oneShot":true,"skipIf":"approved or leadSourceProvider or yolo_mode auto-selected source_lane_approved","requiredBeforeTools":["get_provider_prompt","search_signals","search_sales_nav","search_prospeo","fetch_post_engagers"],"requiredInlineFields":["plain-language buyer groups or places for this campaign","best place to start","why the right buyers are likely to be there","what signs the next search will check","where to look next if the first place is too thin","what approval authorizes"],"choices":["Start with LinkedIn posts","Start with active LinkedIn profiles","Start with company/contact search","Choose a different place","Pause here"],"approvalChoiceLabelsByProvider":{"signal-discovery":"Start with LinkedIn posts","sales-nav":"Start with active LinkedIn profiles","prospeo":"Start with company/contact search"},"approvalState":"source_lane_approved","copyMustAvoid":["lane","source scouting","provider","precision/scale tradeoff","evidence quality","pilot volume","ICP","workflow pain","lead-source scouting","not importing leads"],"copyMustInclude":["Find Buyers Plan","best place to start","I won't add anyone","choose where to find buyers"]},{"action":"persist_provider_search_step_before_search","tool":"update_campaign","requiredPrecondition":"source_lane_approved","providerCurrentStepMap":{"signal-discovery":"signal-discovery","sales-nav":"sales-nav","prospeo":"prospeo"},"requiredValues":{"leadSourceType":"new","leadSourceProvider":"approved provider","currentStep":"provider-specific current step","watchNarration.stage":"find-leads","watchNarration.headline":"Searching the approved place","watchNarration.safety":"Looking only. No one is added yet."},"mustRunBefore":["search_signals","search_sales_nav","search_prospeo","fetch_post_engagers"]},{"action":"run_sequential_source_funnel","requiredPrecondition":"source_lane_approved","defaultOrder":["source-scout-linkedin-engagement","source-scout-sales-nav","source-scout-prospeo-contact"],"campaignOfferIdRequired":true,"stopOnFirstViableUnlessComparisonRequested":true}],"requiredCampaignState":["campaignId","campaignBrief","currentStep"],"allowedTools":["get_source_scout_registry","get_provider_prompt","lookup_sales_nav_filter","search_sales_nav","search_prospeo","search_signals","select_promising_posts","fetch_post_engagers","fetch_company","fetch_linkedin_profile","load_csv_linkedin_leads","load_csv_domains","get_rows_minimal","update_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign"],"waitFor":["lead_review_ready","revise_brief","confirm_with_user"],"transitions":{"lead_review_ready":"lead-review","revise_brief":"brief-interview","confirm_with_user":"lead-review"}},{"id":"lead-review","label":"Source approval","onEnter":[{"action":"show_source_decision_card","requiredInlineFields":["primary source and exact filters/recipe","specific source action awaiting approval","for Signal Discovery: compact Source Recommendation in plain language with selected posts, people to check, likely prospects, first review, and fallback","for Signal Discovery: recommended scrape post count and target people-to-check volume","first campaign review size, clearly separate from source sampling","runner-up and why it lost","raw volume","sampled people","sampled fits as n/N plus percentage/range","estimated usable prospects","cleanup risk","what approval authorizes"],"copyMustAvoid":["lead-source scouting","source scouting","headline-fit","engagers needed","execution slice","ICP","good buyers","real buyers"]},{"action":"ask_source_review_choice","uses":"request_user_input","choices":["Approve scraping N recommended LinkedIn posts","Run the approved source import","Revise source","Pause here"],"approvalChoiceLabelsByProvider":{"signal-discovery":"Approve scraping {scrapePostCount} recommended LinkedIn posts?","sales-nav":"Import the approved Sales Nav source list","prospeo":"Import the approved Prospeo source list"},"postApprovalContract":{"singleUseApproval":true,"doNotRepeatAfterApproval":["Source Recommendation","show_source_decision_card","ask_source_review_choice"],"requiredNextActionAfterApproval":"ack once; call import_leads immediately","signalDiscoveryNextTool":"import_leads({ provider: \"signal-discovery\", targetEngagerCount, maxPostsToScrape, confirmed: true })"},"autoSelectIf":"yolo_mode and projected usable pool clears the source quality floor"}],"requiredCampaignState":["campaignId","campaignBrief","providerSearchAssociation"],"allowedTools":["AskUserQuestion","request_user_input","update_campaign"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign"],"waitFor":["lead_review_confirmed","revise_leads","confirm_with_user","auto_continue"],"transitions":{"lead_review_confirmed":"auto-execute-leads","revise_leads":"find-leads","confirm_with_user":"auto-execute-leads","auto_continue":"auto-execute-leads"}},{"id":"auto-execute-leads","label":"Materialize confirmed source list","currentStepValue":"auto-execute-leads","reference":"references/step-13-import-leads.md","onEnter":[{"tool":"get_subskill_prompt","requiredValues":{"subskillName":"create-campaign-v2-tail"},"purpose":"load tail contract before execution tools"},{"tool":"import_leads","requiredFields":["campaignOfferId","selected source/list","sourceListTarget or targetEngagerCount"],"requiredValues":{"salesNavProspeoDefaultSourceListTarget":1000,"signalDiscoveryDefaultEngagerTarget":1500},"modeAddHandshake":{"firstCallReturns":"needsModeSelection when adding to an existing campaign-attached list","requiredFollowup":"retry with mode=add after explicit user/source-state compatibility is confirmed"},"surfaceDedupRatio":true},{"tool":"wait_for_lead_list_ready"},{"tool":"confirm_lead_list","requiredFields":["campaignOfferId","selectedLeadListId","reviewBatchLimit"],"requiredValues":{"reviewBatchLimit":15},"capture":["workflowTableId","reviewBatchRowIds"]},{"tool":"wait_for_campaign_table_ready"},{"tool":"get_rows_minimal","requiredValues":{"tableId":"{workflowTableId}","limit":15},"capture":["reviewBatchRowHash"]},{"action":"summarize_review_batch_and_advance_to_filter_choice","purpose":"ask filter choice immediately; no post-lead registries, filter refs, or message prompts first","maxCustomerCopyLines":4}],"requiredCampaignState":["campaignId","providerSearchAssociation","selectedLeadListId"],"allowedTools":["get_subskill_prompt","import_leads","wait_for_lead_list_ready","confirm_lead_list","wait_for_campaign_table_ready","get_rows_minimal","update_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["get_post_find_leads_scout_registry","Task","spawn_agent","list_senders","queue_cells","start_campaign","enrich_with_prospeo","bulk_enrich_with_prospeo","save_rubrics"],"waitFor":"source_list_confirmed_and_review_sample_ready","transitions":{"source_list_confirmed_and_review_sample_ready":"filter-choice","escalation_triggered":"escalation"}},{"id":"filter-choice","label":"Filter choice","currentStepValue":"filter-choice","onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"filter-choice","watchNarration.stage":"fit-message"}},{"action":"ask_filter_choice","uses":"request_user_input","choices":["Use filters","Skip filters","Revise source"],"autoSelectIf":"yolo_mode; choose filters unless source is tightly curated or user directed otherwise"}],"hardRules":["ask_filter_choice_immediately_after_review_batch_import","do_not_call_get_subskill_prompt_before_filter_choice","do_not_call_get_subskill_asset_before_filter_choice","do_not_call_get_post_find_leads_scout_registry_before_filter_choice","do_not_spawn_post_lead_agents_before_filter_choice"],"requiredCampaignState":["campaignId","campaignBrief","selectedLeadListId","workflowTableId"],"allowedTools":["AskUserQuestion","request_user_input","update_campaign","get_campaign_navigation_state"],"doNotAllow":["get_subskill_prompt","get_subskill_asset","get_post_find_leads_scout_registry","Task","spawn_agent","create_campaign","list_senders","import_leads","confirm_lead_list","queue_cells","start_campaign","generate_messages"],"waitFor":["filters_enabled","filters_skipped","revise_leads"],"transitions":{"filters_enabled":"post-lead-workstreams","filters_skipped":"message-generation","revise_leads":"find-leads"}},{"id":"post-lead-workstreams","label":"Filter workstream","onEnter":[{"action":"persist_add_filters_approval","tool":"update_campaign","when":"filters_enabled","requiredFields":["campaignId","enableICPFilters","currentStep","watchNarration"],"requiredValues":{"enableICPFilters":true,"currentStep":"create-icp-rubric","watchNarration.stage":"fit-message","watchNarration.headline":"Create filter rules","watchNarration.visibleState":"Filters are enabled and the browser is showing Filter Rules while Codex defines the rubric.","watchNarration.nextAction":"Review saved filter rules"},"mustRunBefore":["get_post_find_leads_scout_registry","launch_lead_fit_builder_after_filter_choice","save_rubrics"]},{"tool":"get_post_find_leads_scout_registry","purpose":"load canonical post-lead worker names only after the user has chosen filters"},{"action":"launch_lead_fit_builder_after_filter_choice","mode":"parallel_when_host_supports_subagents","target":"post-find-leads-filter-scout","inputs":["campaignId","campaignBrief","selectedLeadListId","workflowTableId","reviewBatchRowIds/hash","filterChoice"],"stateSource":"live campaign/table","debugFilesOptionalOnly":true},{"action":"launch_message_draft_builder_after_filter_decision","mode":"parallel_when_host_supports_subagents","target":"post-find-leads-message-scout","when":"filters_enabled","doesNotQueueCells":true,"customerNarration":"Say message agent is drafting."},{"action":"save_filter_rubrics_to_campaign","tool":"save_rubrics","when":"filters_enabled and rubrics are production-shaped","requiredFields":["campaignOfferId","leadScoringRubrics"],"writesCampaignState":"leadScoringRubrics","requiredSideEffects":{"enableICPFilters":true,"currentStep":"create-icp-rubric","watchNarration.headline":"Filter rules saved for review"}},{"action":"ask_filter_rubric_review_choice","uses":"request_user_input","choices":["Approve filters","Revise filters","Pause"],"purpose":"let the user read saved rubrics before Filter Leads or enrichment","copyMustInclude":["These rules prevent wasted sends before I score/import the list.","Recommended because of the researched ICP, source sample, and repeated false-positive patterns.","one pass example and one block example when available","Approval here means approving filter rules, not message drafts or campaign launch."],"autoSelectIf":"yolo_mode and rubrics are production-shaped"}],"requiredCampaignState":["campaignId","campaignBrief","selectedLeadListId","workflowTableId"],"allowedTools":["get_subskill_prompt","get_subskill_asset","get_post_find_leads_scout_registry","save_rubrics","get_campaign","get_rows_minimal","update_campaign","get_campaign_navigation_state","AskUserQuestion","request_user_input","Task","spawn_agent"],"doNotAllow":["create_campaign","list_senders","import_leads","confirm_lead_list","queue_cells","start_campaign","check_rubric","generate_messages"],"waitFor":["filter_rubrics_approved","revise_leads","revise_rubric","revise_messaging"],"hardRules":["after_save_rubrics_currentStep_must_stay_create-icp-rubric_until_filter_approval","filter_approval_required_before_apply-icp-rubric_or_queue_cells","do_not_move_browser_to_messages_until_filter_leads_step_is_current_or_filters_are_explicitly_skipped","no_post_lead_worker_or_deep_prompt_before_filter_choice","lead_fit_builder_starts_only_after_filters_enabled","msg_draft_after_filter_choice","msg_draft_no_cells"],"transitions":{"filter_rubrics_approved":"message-generation","revise_leads":"find-leads","revise_rubric":"filter-rubric","revise_messaging":"message-generation","confirm_with_user":"message-review"}},{"id":"filter-rubric","label":"Rubric revision","onEnter":[{"tool":"get_subskill_asset","requiredValues":{"subskillName":"create-campaign-v2","assetPath":"references/filter-leads.md"}},{"tool":"save_rubrics","requiredFields":["campaignOfferId","leadScoringRubrics"],"writesCampaignState":"leadScoringRubrics","requiredSideEffects":{"enableICPFilters":true,"currentStep":"create-icp-rubric","watchNarration.headline":"Filter rules saved for review"}},{"action":"ask_filter_rubric_review_choice","uses":"request_user_input","choices":["Approve filters","Revise filters","Pause"],"copyMustInclude":["These rules prevent wasted sends before I score/import the list.","approval object is filter rules only","not campaign launch"],"autoSelectIf":"yolo_mode and rubrics are production-shaped"}],"requiredCampaignState":["campaignId","workflowTableId"],"allowedTools":["get_subskill_asset","save_rubrics","AskUserQuestion","request_user_input"],"doNotAllow":["create_campaign","list_senders","import_leads","confirm_lead_list","update_campaign","queue_cells","start_campaign","check_rubric"],"waitFor":["filter_rubrics_approved","revise_leads","confirm_with_user","auto_continue"],"transitions":{"filter_rubrics_approved":"message-generation","revise_leads":"find-leads","confirm_with_user":"message-generation","auto_continue":"message-generation"}},{"id":"message-generation","label":"Message generation","onEnter":[{"action":"set_message_review_visible_step_by_filter_choice","tool":"update_campaign","branchRules":["yes after filter approval: currentStep=apply-icp-rubric; wait on Filter Leads","no: currentStep=messages; message review"],"watchNarration.stage":"fit-message"},{"action":"run_or_reconcile_message_draft_builder","target":"post-find-leads-message-scout","toolCallRequiredBeforeDraft":["run background post-find-leads-message-scout when available","get_subskill_prompt({ subskillName: \"generate-messages\", offset, limit }) until hasMore=false"],"stateSource":"campaignBrief, source, selectedLeadListId, workflowTableId, execution-slice row ids/hash","outputState":"messageDraftRecommendation"}],"requiredCampaignState":["campaignId","campaignBrief","selectedLeadListId","workflowTableId"],"allowedTools":["get_subskill_prompt","get_campaign","get_rows_minimal","update_campaign","AskUserQuestion","request_user_input"],"toolRules":["Run post-find-leads-message-scout when available; otherwise parent fallback must load get_subskill_prompt({ subskillName: \"generate-messages\" }) from live state.","brief.md, lead-review.md, and lead-sample.json are optional debug context only.","messageDraftRecommendation returns templateRecommendation, tokenFillRules, renderedSample, concerns, status, basisToken, outputAt, outputHash, and error/retry detail.","If campaign/source/table/execution-slice basis does not match, classify the output stale or blocked."],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign","generate_messages"],"waitFor":["message_validation_ready","revise_rubric","revise_messaging","confirm_with_user","auto_continue"],"transitions":{"message_validation_ready":"message-review","revise_rubric":"filter-rubric","revise_messaging":"message-generation","confirm_with_user":"message-review","auto_continue":"message-review"}},{"id":"message-review","label":"Message review","onEnter":[{"action":"render_message_review_from_state","requiredState":["campaignBrief","selectedLeadListId","workflowTableId","messageDraftRecommendation"],"requiredVisibleLabels":["## Message Template","## Rendered Example","Good token fill:","My take:","Question: approve-message or revise-messaging?","Recommendation:"],"doNotShowByDefault":["Token Notes","Good omit / fallback","Bad fill to avoid","Token Adherence Table"],"internalPersistenceOnly":["Token Fill Rules","Token Fill Examples","fallback guidance","bad-fill avoidance notes"],"copyMustInclude":["QA receipt before approval","tokens resolved","company/person match","proof claim","prospect angle","language/tone when known","obvious bad fits","Would I take this call?","weak personalization can burn the sender's reputation","full list remains paused"]},{"action":"ask_message_review_choice","uses":"request_user_input","choices":["approve-message","revise-messaging"],"copyMustInclude":["approve the message direction only","not campaign launch","not LinkedIn sender approval"],"autoSelectIf":"yolo_mode and Recommendation is approve-message; revise autonomously when Recommendation is revise-messaging"},{"action":"sync_approved_message_set_to_campaign_brief","tool":"update_campaign_brief","when":"after approve-message","requiredFields":["campaignId","approvedMessageTemplate","Token Fill Rules","Token Fill Examples"],"writesCampaignState":"approvedMessageTemplate"}],"requiredCampaignState":["campaignId","workflowTableId","messageDraftRecommendation"],"allowedTools":["AskUserQuestion","request_user_input","update_campaign_brief","update_campaign","get_rows_minimal"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","start_campaign"],"waitFor":["message_approved","revise_messaging"],"transitions":{"message_approved":"validate-sample","revise_messaging":"message-generation"}},{"id":"validate-sample","label":"Validate campaign-table execution slice","currentStepValue":"apply-icp-rubric","reference":"references/sample-validation-loop.md","visibleStepRule":"Filter Leads is reached only after saved-filter approval. On approve-message, save the template, refresh apply-icp-rubric narration, then queue bounded Enrich Prospect cells.","onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"apply-icp-rubric","watchNarration.stage":"fit-message"},"purpose":"keep the watched UI on Filter Leads while the approved template starts the bounded cascade","watchNarrationRule":"Say the template is saved and Filter Leads is now running the bounded enrichment and scoring pass."},{"tool":"queue_cells","purpose":"queue ICP/enrichment cells for the internal campaign-table execution slice only","requiredFields":["workflowTableId","reviewBatchRowIds","cellTypes"],"targetCountSource":"reviewBatchRowIds.length (default 15)"},{"tool":"wait_for_campaign_table_ready","purpose":"wait_for_review_batch_scoring_cells"},{"tool":"get_rows_minimal","requiredValues":{"includeRows":false},"purpose":"read compact row status only"},{"tool":"wait_for_rubric_results","requiredFields":["workflowTableId","targetCount","minPassedCount"],"requiredValues":{"includeRows":false,"minPassedCount":1},"minPassedCountSource":"firstPassingRowForMessageStart","readVia":"stats_only_tool_result","customerSummaryPattern":["{checked} leads checked","{passed} passed and have draft messages","{blocked} blocked before sending","full list remains paused until approval"]},{"action":"handle_partial_or_timeout_sample","customerStatus":"sample-needs-revision","rule":"Do not repeat waits indefinitely; surface partial status and route to revision.","copyMustInclude":"completed, passed, pending, blocked before sending, and full list remains paused"}],"requiredCampaignState":["campaignId","workflowTableId","approvedMessageTemplate","filterRubricsApproved when enableICPFilters=true"],"allowedTools":["get_subskill_asset","queue_cells","wait_for_campaign_table_ready","get_rows_minimal","wait_for_rubric_results","update_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["import_leads","list_senders","start_campaign","enrich_with_prospeo","bulk_enrich_with_prospeo","check_rubric"],"hardRules":["wait_for_rubric_results_never_retain_rows_payload_in_tail_context","wait_for_rubric_results_targetCount_always_explicit","timeout_never_repeats_without_customer_handoff","timeout_or_underfloor_sample_never_advances_to_settings"],"waitFor":["sample_validated","sample_revision_required"],"transitions":{"sample_validated":"auto-execute-messaging","sample_revision_required":"lead-review","revise_leads":"find-leads","revise_rubric":"filter-rubric","escalation_triggered":"escalation"}},{"id":"auto-execute-messaging","label":"Generate initial campaign-row messages","currentStepValue":"auto-execute-messaging","references":["references/parallel-critique-protocol.md","references/thomas-variant-selection.md","references/thomas-revision-filters.md","references/step-15-re-cascade.md"],"onEnter":[{"tool":"queue_cells","batchSize":100,"when":"any passing row has pending or empty Generate Message cell","cellSource":"pending_generate_message_cells_for_passing_rows using approved_campaign_brief_template"},{"tool":"wait_for_rubric_results","purpose":"wait_for_first_passing_generated_message","requiredValues":{"includeRows":false,"minPassedCount":1,"minMessagesCount":1},"readVia":"stats_only_tool_result"},{"action":"observe_generate_message_results","reference":"references/step-15-re-cascade.md"},{"action":"enforce_token_contract","modeFromConfig":"messaging.tokenContract"},{"action":"optional_critique_pass","enabledFromConfig":"messaging.critique.enabled","plan":"85-03","protocol":"references/parallel-critique-protocol.md","sampleSizeFromConfig":"messaging.critique.sampleSize","budgetUsdCapFromConfig":"messaging.critique.budgetUsdCap","perCriticTimeoutFromConfig":"messaging.critique.perCriticTimeoutSeconds","totalTimeoutFromConfig":"messaging.critique.totalTimeoutSeconds","criticsFromConfig":"messaging.critique.critics","enforceFinalizerPassFromConfig":"messaging.critique.synthesis.enforceFinalizerPass","rejectOnFakeProofFromConfig":"messaging.critique.rejectOnFakeProof","rejectOnUnsupportedTokenFromConfig":"messaging.critique.rejectOnUnsupportedToken","onBudgetTrip":"halt_critique_continue_plain_tail","onPerCriticTimeout":"drop_critic_proceed_with_remaining","onTotalTimeout":"persist_plain_message_for_row","onTokenContractViolation":"persist_plain_message_for_row","onFakeProof":"persist_plain_message_for_row"},{"action":"optional_opus_subset","enabledFromConfig":"messaging.critique.opus.enabled","selection":"references/thomas-variant-selection.md","maxMessagesPerPassFromConfig":"messaging.critique.opus.maxMessagesPerPass","budgetUsdCapFromConfig":"messaging.critique.opus.budgetUsdCap","onOpusBudgetTrip":"halt_opus_continue_non_opus","onOpusTokenContractViolation":"fallback_to_non_opus_rewrite"},{"tool":"update_campaign","requiredValues":{"currentStep":"auto-execute-messaging","watchNarration.stage":"review-ready"},"watchNarrationRule":"Say the first passing generated message is ready in Messages; next is review before Settings."},{"action":"ask_generated_message_review_choice","uses":"request_user_input","choices":["Approve reviewed draft rows and continue to Settings","Revise filters","Revise message template","Pause here"],"copyMustInclude":["approve these draft rows for the next review step","not approving the full campaign launch","not approving the user's LinkedIn account for sending yet","tokens resolved","company/person match","proof claim","prospect angle","language/tone when known","obvious bad fits","Would I take this call?","weak personalization can burn the sender's reputation","full list remains paused"],"autoSelectIf":"yolo_mode and the first passing generated message clears the quality floor"}],"allowedTools":["get_subskill_asset","get_rows_minimal","queue_cells","wait_for_rubric_results","update_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["import_leads","list_senders","start_campaign","generate_messages"],"hardRules":["critique_failure_never_escalates","critique_sample_size_bounded_by_config","first_passing_generated_message_unblocks_review","critics_fixed_at_targeting_copy_voice","synthesis_enforces_phase_84_token_contract","opus_reserved_for_highest_value_subset","proposed_token_never_persisted_in_rewrite"],"waitFor":["generated_messages_approved","sample_revision_required"],"transitions":{"generated_messages_approved":"awaiting-user-greenlight","revise_filters":"filter-rubric","revise_messaging":"message-generation","escalation_triggered":"escalation"}},{"id":"awaiting-user-greenlight","label":"Settings, sender, sequence, and greenlight","currentStepValue":"awaiting-user-greenlight","reference":"references/final-handoff-contract.md","onEnter":[{"tool":"get_campaign","purpose":"verify senderIds and sequence state before final handoff"},{"tool":"list_senders","purpose":"surface available connected senders only at Settings"},{"tool":"update_campaign","requiredValues":{"currentStep":"settings","watchNarration.stage":"review-ready"},"purpose":"park the watched UI on Settings before sender selection","watchNarrationRule":"Say message review is complete and the browser is now on Settings so the user can connect or choose a sender. Include that lead research and filtering already happened outside the user's LinkedIn account, this sender is only used for approved sending after final launch, and no launch happens from Settings."},{"action":"surface_sender_and_slack_handoff","requiredVisibleContent":["connect or select a LinkedIn sender","Lead research and filtering already happened outside your LinkedIn account.","This account is only used for approved sending after final launch.","Nothing sends until the final Start step.","Slack reply review","recommended sequence","final launch confirmation is still ahead"]},{"action":"ask_sender_selection","uses":"request_user_input","singleChoice":true,"choices":["Use this connected sender","Connect a different sender in Settings","Pause here"],"autoSelectIf":"yolo_mode and exactly one safe connected sender is available"},{"action":"attach_selected_sender","tool":"update_campaign","when":"user selected an available connected sender","requiredValues":{"senderIds":["{selectedSenderId}"],"currentStep":"sequence","watchNarration.stage":"review-ready"},"watchNarrationRule":"Say the sender was attached and the browser is moving to Sequence review. Include that the sequence is editable before launch and still not sending until Start."},{"tool":"attach_recommended_sequence","when":"after senderIds are attached","requiredValues":{"campaignId":"{campaignId}","currentStep":"send","watchNarration.stage":"review-ready"},"watchNarrationRule":"The sequence tool owns the visible beat: say the recommended follow-up sequence is attached, the browser is now on final launch review, and the next action is final launch greenlight. Include that it is still not sending until Start. Do not follow with a separate step-only update_campaign fixup."},{"action":"ask_final_launch_greenlight","uses":"request_user_input","singleChoice":true,"choices":["Start campaign","Review campaign first","Pause here"],"copyMustInclude":["quality confidence means sample messages and prospect angle were checked","launch confidence means sender, sequence, and Start are ready","approved messages begin sending according to the sequence","replies and meetings follow connected settings","you can monitor and pause","no hidden extra approval disappears after clicking Start"],"onUserStart":"claude-greenlight","neverAutoSelectInYolo":true}],"allowedTools":["get_campaign","get_campaign_navigation_state","list_senders","update_campaign","attach_recommended_sequence","AskUserQuestion","request_user_input"],"doNotAllow":["start_campaign","import_leads"],"autoStart":false,"watchRequired":true,"waitFor":["sender_connection_required","sender_attached","sequence_attached","ready_to_launch","user_greenlight","ui_start_detected"],"transitions":{"sender_connection_required":"awaiting-user-greenlight","sender_attached":"awaiting-user-greenlight","sequence_attached":"awaiting-user-greenlight","ready_to_launch":"awaiting-user-greenlight","user_greenlight":"claude-greenlight","ui_start_detected":"running"}},{"id":"claude-greenlight","label":"Explicit launch","reference":"references/final-handoff-contract.md","onEnter":[{"tool":"get_campaign","purpose":"detect_already_running"},{"action":"verify_sequence_and_current_step_before_start","requiredState":["workflowTableId","senderIds","sequenceTemplate","at least one approved generated message","currentStep in awaiting-user-greenlight|claude-greenlight|send"]},{"tool":"start_campaign","requiredFields":["campaignId"],"persistsCurrentStep":"running","watchNarrationRule":"After start_campaign succeeds, the running state must say the final greenlight was accepted, the campaign is now live/running, and the user can watch progress from the campaign."}],"allowedTools":["get_campaign","attach_recommended_sequence","start_campaign","AskUserQuestion","request_user_input"],"watchRequired":true,"waitFor":"campaign_started","transitions":{"campaign_started":"running"}},{"id":"running","label":"Campaign is live","currentStepValue":"running","onEnter":[{"action":"surface_watch_link"},{"action":"surface_campaign_live_confirmation"}],"allowedTools":["get_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["start_campaign"],"terminal":true},{"id":"escalation","label":"Escalation","reference":"references/escalation-ladder.md","allowedTools":["AskUserQuestion","request_user_input"],"doNotAllow":["start_campaign","import_leads"],"transitions":{"revise_brief":"brief-interview","revise_leads":"find-leads","revise_rubric":"filter-rubric","revise_messaging":"message-generation","abort":"abort"}},{"id":"abort","label":"Abort","allowedTools":["AskUserQuestion","request_user_input"],"terminal":true}]}
1
+ {"version":"v2.1-compact","workflow":"create-campaign-v2","principle":"CampaignOffer state and watch link are canonical. Create the watched shell, approve source, materialize and confirm the source list, internally process the first campaign-table execution slice, save rubrics for approval, approve the message template, then run the bounded filter/message cascade before Settings, sequence, and explicit start.","normalCustomerPath":"Use campaign state, MCP responses, and concise watchNarration. Do not create, read, link, or surface local draft files.","legacyCompatibility":{"validationSubskill":"create-campaign-v2-validation","tailSubskill":"create-campaign-v2-tail","rule":"Legacy validation/rehearsal files are opt-in diagnostics only and are not active flow gates."},"commitGateChoices":["approve","revise-brief","revise-leads","revise-rubric","revise-messaging","abort"],"canonicalStateFields":["campaignId","watchUrl","campaignBrief","currentStep","watchNarration","interactionMode","providerSearchAssociation","selectedLeadListId","workflowTableId","filterChoice","leadScoringRubrics","messageDraftRecommendation","approvedMessageTemplate","senderIds","sequenceTemplate","runningState"],"watchNarrationTransitionContract":{"rule":"Every watched currentStep switch must include fresh watchNarration.","requiredFields":["stage","headline","visibleState","agentIntent","nextAction"],"copyMustInclude":["what just happened","current visible page/state","next user action"],"appliesToTools":["create_campaign","update_campaign","attach_recommended_sequence","start_campaign"]},"lazyReferences":{"watch":["references/watch-link-handoff.md","references/watch-guide-narration.md"],"source":["references/lead-validation-preview.md","references/step-13-import-leads.md"],"filter":["references/filter-leads.md"],"message":[],"tail":["references/sample-validation-loop.md","references/step-15-re-cascade.md","references/final-handoff-contract.md"]},"safetyBoundaries":["Do not call list_senders before Settings after message approval.","Do not import leads until the source decision is approved.","Do not queue cells until confirmed source rows exist in the campaign and the message/filter gates are satisfied.","Do not call start_campaign until the user explicitly confirms launch.","Do not use local files as durable state in normal customer runs."],"yoloMode":{"triggerPhrases":["yolo","--yolo","mode=yolo","autopilot","use best guesses","use best estimates","answer for me","just run it"],"identityRequestOnlyWhenMissing":true,"operatorDirectionsRule":"Treat freeform directions supplied at invocation or later as durable operator directions; newest conflicting direction wins.","setInteractionModeAfterCampaignCreate":"autonomous","autoSelectsPreLaunchChoices":["campaign focus","brief approval","source plan","source review/import approval","filters vs skip filters","filter rubric approval","message template approval when recommendation is approve-message","generated message review when quality floor passes","sender selection when exactly one connected sender is safe"],"mustPauseFor":["missing LinkedIn profile URL","missing credentials or required data","ambiguous choice with no reasonable estimate","source/message/filter quality floor failure","final live launch confirmation"],"neverAutoStart":true},"steps":[{"id":"bootstrap","label":"Bootstrap","onEnter":[{"tool":"bootstrap_create_campaign","requiredValues":{"flowVersion":"v2"}},{"tool":"get_subskill_prompt","requiredValues":{"subskillName":"create-campaign-v2"},"purpose":"load the compact entry prompt once"}],"allowedTools":["bootstrap_create_campaign","get_auth_status","get_active_workspace","get_subskill_prompt","AskUserQuestion","request_user_input"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","update_campaign","queue_cells","start_campaign"],"waitFor":"bootstrap_complete","transitions":{"bootstrap_complete":"brief-interview"}},{"id":"brief-interview","label":"Client, offer, research, and brief","onEnter":[{"action":"resolve_campaign_identity_before_strategy_packet","allowedTools":["fetch_company","fetch_linkedin_profile","WebFetch","WebSearch"],"mustNotInferFromNameOnly":true,"doNotPresentSenderPickerBeforeIdentityInference":true,"fallback":"Ask only: \"What is your LinkedIn profile URL?\" If the user provides a non-profile URL, company page, or anything else, ask again for the person's LinkedIn profile URL before strategy questions.","requiresLinkedInProfileUrl":true,"doNotAcceptAsIdentityInput":["non-profile URL","company page","anything other than a LinkedIn profile URL"]},{"action":"run_campaign_identity_research_before_strategy_packet","target":"research-sender","requiredCompletion":"complete_sender_research","allowedTools":["get_subskill_prompt","fetch_linkedin_profile","fetch_company","fetch_linkedin_posts","fetch_company_posts","WebFetch","WebSearch","complete_sender_research"],"requiredInput":"LinkedIn profile URL"},{"action":"confirm_target_before_strategy_packet","uses":"request_user_input","singleChoice":true,"question":"Who should we target first?","options":["Use Sellable's researched recommendation","Choose a different buyer","I'm not sure yet"],"copyMustInclude":["research basis","recommendation is editable","who to target"],"requiredOption":"Other / custom","neverCollectOpenTextWithStructuredQuestion":true,"skipIf":"user already supplied a clear target or yolo_mode with any reasonable best-estimate target"},{"action":"confirm_current_offer_before_strategy_packet","uses":"request_user_input","question":"What offer should this campaign lead with?","options":["Use Sellable's researched recommendation","Use my current offer","Shape the offer together"],"copyMustInclude":["research basis","public LinkedIn research may be stale","recommendation is editable"],"skipIf":"user already supplied a clear current offer or yolo_mode with any reasonable researched recommendation"},{"action":"confirm_trust_proof_before_strategy_packet","uses":"request_user_input","singleChoice":true,"question":"What is the strongest credibility signal we can lead with?","options":["Use Sellable's recommended proof","Use customer proof or a case study","Use founder or company credibility"],"copyMustInclude":["build trust with prospects","recommendation is editable","proof to use or avoid"],"requiredOption":"Other / custom","skipIf":"user already supplied clear proof to use or avoid, or yolo_mode with any reasonable researched proof"},{"action":"choose_prospect_source_path_before_strategy_packet","uses":"request_user_input","singleChoice":true,"question":"How should we find prospects?","options":["Find prospects for me","Use a CSV of LinkedIn profiles","Use a CSV of company domains"],"copyMustInclude":["prospects","no one added yet","find prospects for me"],"skipIf":"user already supplied a source path or yolo_mode with any reasonable source path"},{"action":"infer_strategy_packet_in_yolo_mode","when":"yolo_mode","skipStructuredSetupQuestions":true,"inferFields":["buyer segment","offer/CTA","proof to use or avoid","lead source","filter choice","message direction"],"sourceOfTruth":"identity/company lookup plus operator directions","mustStateAssumptionsInBrief":true},{"action":"create_watchable_campaign_shell_with_v1_brief","tool":"create_campaign","requiredFields":["name","campaignBrief","clientProspectId or senderLinkedinUrl","currentStep","watchNarration"],"requiredValues":{"currentStep":"create-offer","watchNarration.stage":"brief"},"capture":["campaignId","watchUrl"],"canonicalStateWrites":["campaignId","watchUrl","campaignBrief","currentStep:create-offer"]},{"action":"surface_campaign_shell_watch_link","watchUrlSource":"create_campaign.watchUrl","requiredWatchUrlShape":"direct /campaign-builder/{campaignId}?mode={claude|codex} watch URL with token auto-login and workspace routing","copyMustInclude":["We'll keep building the campaign in this chat.","You can watch it come together in real time here:","I'll ask for your approval whenever I need your expertise or taste before moving forward.","Send changes here in chat."],"immediateNextMainChatLine":"Next, we'll choose where to find buyers. I won't add anyone yet.","codexBrowserHandoff":{"openWhenAvailable":false,"printWatchLinkOnly":true,"tellUserCommandEnterOrClick":false,"mustNotUseBrowserAutomation":true,"fallbackMustNotClaimInspection":true}}],"allowedTools":["get_subskill_prompt","fetch_company","fetch_company_posts","fetch_linkedin_profile","fetch_linkedin_posts","complete_sender_research","create_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign"],"waitFor":["campaign_shell_created","brief_ready","confirm_with_user"],"transitions":{"campaign_shell_created":"brief-review","brief_ready":"brief-review","confirm_with_user":"brief-review"}},{"id":"brief-review","label":"Brief review","onEnter":[{"action":"render_brief_inline","minimumVisibleDetail":"campaign direction, buyer, offer, proof, source plan, safety gates","copyMustInclude":["compact provenance labels: [from you], [from LinkedIn], [from website], [from case study], or [Sellable recommendation]","This is based on what I found. If your site or LinkedIn is stale, tell me what to update before I build the lead list.","Do you agree with this researched campaign direction?"],"copyMustNotInclude":["quoted first-message copy","Message Angle as final proof"],"messageHintRule":"If any message-shape hint remains, keep it as non-final bullets and say real examples come after leads are found and filtered."},{"action":"ask_brief_choice","uses":"request_user_input","choices":["Approve brief","Revise brief","Pause here"],"skipIf":"yolo_mode; auto_continue after rendering assumptions unless brief quality floor fails"}],"requiredCampaignState":["campaignId","watchUrl","campaignBrief","currentStep"],"allowedTools":["AskUserQuestion","request_user_input","update_campaign"],"doNotAllow":["create_campaign","list_senders","import_leads","confirm_lead_list","queue_cells","start_campaign"],"waitFor":["user_brief_confirmed","revise_brief","auto_continue"],"transitions":{"user_brief_confirmed":"find-leads","revise_brief":"brief-interview","auto_continue":"find-leads"}},{"id":"find-leads","label":"Find leads","sourceSelectionFunnel":{"preScoutRecommendationGate":{"required":true,"label":"Find buyers plan approval","mustHappenBefore":["get_provider_prompt","search_signals","search_sales_nav","search_prospeo","fetch_post_engagers","source-scout dispatch"],"show":["buyer groups or places we could check","best place to start","why the right buyers are likely to be there","what signs the next search will check","where to look next if the first place is too thin","what approval authorizes"],"approvalAuthorizes":"looking for the best places to find buyers; no one added yet","explanationMustInclude":["where the right buyers are already talking","why that place fits this campaign","enough likely prospects","what counts as a good sign","where to look next if thin","I won't add anyone yet","choose where to find buyers"],"yoloMode":{"autoApproveRecommendedLane":true,"mustShowAssumedChoice":true,"pauseIfConfidenceLow":true},"customerLanguage":{"readability":"grade-5","requiredHeading":"Find Buyers Plan","prefer":["place to look","best place to start","people to check","prospects","I won't add anyone yet"],"avoid":["lane","source scouting","provider","precision/scale tradeoff","evidence quality","pilot volume","ICP","workflow pain","lead-source scouting","not importing leads"],"example":"Brief approved. Next, we'll choose where to find buyers. I won't add anyone yet. I recommend starting with people already talking on LinkedIn about [plain topic]. That should help us find people who already care about [plain problem]. If this is too thin, I'll try [plain fallback] next.","termRule":{"buyers":"target market","peopleToCheck":"raw reactions/comments before fit is known","prospects":"likely usable people after fit","leads":"campaign rows"}}},"defaultWhenSourceUnspecified":["signal-discovery","sales-nav-recent-active","sales-nav-general","prospeo"],"userFacingFallbackOrder":["LinkedIn posts where the right buyers are already talking","people with the right titles who recently posted on LinkedIn","people with the right titles from a broader LinkedIn search","a broader company and contact search"],"parallelAllowedOnlyWhen":["user explicitly requested source comparison","resuming already-started parallel scouts","first viable source is borderline and one cheap fallback check is needed"]},"onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"pick-provider","watchNarration.stage":"find-leads","watchNarration.headline":"Review where to find buyers","watchNarration.visibleState":"The app is showing source selection before lead finding starts.","watchNarration.agentIntent":"Codex is explaining where it recommends looking first and where it will look next if that is too thin.","watchNarration.nextAction":"Approve where to look first or choose another place","watchNarration.safety":"Only deciding where to look. No one is added yet."},"purpose":"show the visible source-plan approval checkpoint before provider lanes"},{"tool":"get_source_scout_registry","purpose":"load canonical source scout names before optional branch launch"},{"action":"show_pre_scout_source_recommendation","uses":"request_user_input","oneShot":true,"skipIf":"approved or leadSourceProvider or yolo_mode auto-selected source_lane_approved","requiredBeforeTools":["get_provider_prompt","search_signals","search_sales_nav","search_prospeo","fetch_post_engagers"],"requiredInlineFields":["plain-language buyer groups or places for this campaign","best place to start","why the right buyers are likely to be there","what signs the next search will check","where to look next if the first place is too thin","what approval authorizes"],"choices":["Start with LinkedIn posts","Start with active LinkedIn profiles","Start with company/contact search","Choose a different place","Pause here"],"approvalChoiceLabelsByProvider":{"signal-discovery":"Start with LinkedIn posts","sales-nav":"Start with active LinkedIn profiles","prospeo":"Start with company/contact search"},"approvalState":"source_lane_approved","copyMustAvoid":["lane","source scouting","provider","precision/scale tradeoff","evidence quality","pilot volume","ICP","workflow pain","lead-source scouting","not importing leads"],"copyMustInclude":["Find Buyers Plan","best place to start","I won't add anyone","choose where to find buyers"]},{"action":"persist_provider_search_step_before_search","tool":"update_campaign","requiredPrecondition":"source_lane_approved","providerCurrentStepMap":{"signal-discovery":"signal-discovery","sales-nav":"sales-nav","prospeo":"prospeo"},"requiredValues":{"leadSourceType":"new","leadSourceProvider":"approved provider","currentStep":"provider-specific current step","watchNarration.stage":"find-leads","watchNarration.headline":"Searching the approved place","watchNarration.safety":"Looking only. No one is added yet."},"mustRunBefore":["search_signals","search_sales_nav","search_prospeo","fetch_post_engagers"]},{"action":"run_sequential_source_funnel","requiredPrecondition":"source_lane_approved","defaultOrder":["source-scout-linkedin-engagement","source-scout-sales-nav","source-scout-prospeo-contact"],"campaignOfferIdRequired":true,"stopOnFirstViableUnlessComparisonRequested":true}],"requiredCampaignState":["campaignId","campaignBrief","currentStep"],"allowedTools":["get_source_scout_registry","get_provider_prompt","lookup_sales_nav_filter","search_sales_nav","search_prospeo","search_signals","select_promising_posts","fetch_post_engagers","fetch_company","fetch_linkedin_profile","load_csv_linkedin_leads","load_csv_domains","get_rows_minimal","update_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign"],"waitFor":["lead_review_ready","revise_brief","confirm_with_user"],"transitions":{"lead_review_ready":"lead-review","revise_brief":"brief-interview","confirm_with_user":"lead-review"}},{"id":"lead-review","label":"Source approval","onEnter":[{"action":"show_source_decision_card","requiredInlineFields":["primary source and exact filters/recipe","specific source action awaiting approval","for Signal Discovery: compact Source Recommendation in plain language with selected posts, people to check, likely prospects, first review, and fallback","for Signal Discovery: recommended scrape post count and target people-to-check volume","first campaign review size, clearly separate from source sampling","runner-up and why it lost","raw volume","sampled people","sampled fits as n/N plus percentage/range","estimated usable prospects","cleanup risk","what approval authorizes"],"copyMustAvoid":["lead-source scouting","source scouting","headline-fit","engagers needed","execution slice","ICP","good buyers","real buyers"]},{"action":"ask_source_review_choice","uses":"request_user_input","choices":["Approve scraping N recommended LinkedIn posts","Run the approved source import","Revise source","Pause here"],"approvalChoiceLabelsByProvider":{"signal-discovery":"Approve scraping {scrapePostCount} recommended LinkedIn posts?","sales-nav":"Import the approved Sales Nav source list","prospeo":"Import the approved Prospeo source list"},"postApprovalContract":{"singleUseApproval":true,"doNotRepeatAfterApproval":["Source Recommendation","show_source_decision_card","ask_source_review_choice"],"requiredNextActionAfterApproval":"ack once; call import_leads immediately","signalDiscoveryNextTool":"import_leads({ provider: \"signal-discovery\", targetEngagerCount, maxPostsToScrape, confirmed: true })"},"autoSelectIf":"yolo_mode and projected usable pool clears the source quality floor"}],"requiredCampaignState":["campaignId","campaignBrief","providerSearchAssociation"],"allowedTools":["AskUserQuestion","request_user_input","update_campaign"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign"],"waitFor":["lead_review_confirmed","revise_leads","confirm_with_user","auto_continue"],"transitions":{"lead_review_confirmed":"auto-execute-leads","revise_leads":"find-leads","confirm_with_user":"auto-execute-leads","auto_continue":"auto-execute-leads"}},{"id":"auto-execute-leads","label":"Materialize confirmed source list","currentStepValue":"auto-execute-leads","reference":"references/step-13-import-leads.md","onEnter":[{"tool":"get_subskill_prompt","requiredValues":{"subskillName":"create-campaign-v2-tail"},"purpose":"load tail contract before execution tools"},{"tool":"import_leads","requiredFields":["campaignOfferId","selected source/list","sourceListTarget or targetEngagerCount"],"requiredValues":{"salesNavProspeoDefaultSourceListTarget":1000,"signalDiscoveryDefaultEngagerTarget":1500},"modeAddHandshake":{"firstCallReturns":"needsModeSelection when adding to an existing campaign-attached list","requiredFollowup":"retry with mode=add after explicit user/source-state compatibility is confirmed"},"surfaceDedupRatio":true},{"tool":"wait_for_lead_list_ready"},{"tool":"confirm_lead_list","requiredFields":["campaignOfferId","selectedLeadListId","reviewBatchLimit"],"requiredValues":{"reviewBatchLimit":15},"capture":["workflowTableId","reviewBatchRowIds"]},{"tool":"wait_for_campaign_table_ready"},{"tool":"get_rows_minimal","requiredValues":{"tableId":"{workflowTableId}","limit":15},"capture":["reviewBatchRowHash"]},{"action":"summarize_review_batch_and_advance_to_filter_choice","purpose":"ask filter choice immediately; no post-lead registries, filter refs, or message prompts first","maxCustomerCopyLines":4}],"requiredCampaignState":["campaignId","providerSearchAssociation","selectedLeadListId"],"allowedTools":["get_subskill_prompt","import_leads","wait_for_lead_list_ready","confirm_lead_list","wait_for_campaign_table_ready","get_rows_minimal","update_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["get_post_find_leads_scout_registry","Task","spawn_agent","list_senders","queue_cells","start_campaign","enrich_with_prospeo","bulk_enrich_with_prospeo","save_rubrics"],"waitFor":"source_list_confirmed_and_review_sample_ready","transitions":{"source_list_confirmed_and_review_sample_ready":"filter-choice","escalation_triggered":"escalation"}},{"id":"filter-choice","label":"Filter choice","currentStepValue":"filter-choice","onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"filter-choice","watchNarration.stage":"fit-message"}},{"action":"ask_filter_choice","uses":"request_user_input","choices":["Use filters","Skip filters","Revise source"],"autoSelectIf":"yolo_mode; choose filters unless source is tightly curated or user directed otherwise"}],"hardRules":["ask_filter_choice_immediately_after_review_batch_import","do_not_call_get_subskill_prompt_before_filter_choice","do_not_call_get_subskill_asset_before_filter_choice","do_not_call_get_post_find_leads_scout_registry_before_filter_choice","do_not_spawn_post_lead_agents_before_filter_choice"],"requiredCampaignState":["campaignId","campaignBrief","selectedLeadListId","workflowTableId"],"allowedTools":["AskUserQuestion","request_user_input","update_campaign","get_campaign_navigation_state"],"doNotAllow":["get_subskill_prompt","get_subskill_asset","get_post_find_leads_scout_registry","Task","spawn_agent","create_campaign","list_senders","import_leads","confirm_lead_list","queue_cells","start_campaign","generate_messages"],"waitFor":["filters_enabled","filters_skipped","revise_leads"],"transitions":{"filters_enabled":"post-lead-workstreams","filters_skipped":"message-generation","revise_leads":"find-leads"}},{"id":"post-lead-workstreams","label":"Filter workstream","onEnter":[{"action":"persist_add_filters_approval","tool":"update_campaign","when":"filters_enabled","requiredFields":["campaignId","enableICPFilters","currentStep","watchNarration"],"requiredValues":{"enableICPFilters":true,"currentStep":"create-icp-rubric","watchNarration.stage":"fit-message","watchNarration.headline":"Create filter rules","watchNarration.visibleState":"Filters are enabled and the browser is showing Filter Rules while Codex defines the rubric.","watchNarration.nextAction":"Review saved filter rules"},"mustRunBefore":["get_post_find_leads_scout_registry","launch_lead_fit_builder_after_filter_choice","save_rubrics"]},{"tool":"get_post_find_leads_scout_registry","purpose":"load canonical post-lead worker names only after the user has chosen filters"},{"action":"launch_lead_fit_builder_after_filter_choice","mode":"parallel_when_host_supports_subagents","target":"post-find-leads-filter-scout","inputs":["campaignId","campaignBrief","selectedLeadListId","workflowTableId","reviewBatchRowIds/hash","filterChoice"],"stateSource":"live campaign/table","debugFilesOptionalOnly":true},{"action":"launch_message_draft_builder_after_filter_decision","mode":"parallel_when_host_supports_subagents","target":"post-find-leads-message-scout","when":"filters_enabled","doesNotQueueCells":true,"customerNarration":"Say message agent is drafting."},{"action":"save_filter_rubrics_to_campaign","tool":"save_rubrics","when":"filters_enabled and rubrics are production-shaped","requiredFields":["campaignOfferId","leadScoringRubrics"],"writesCampaignState":"leadScoringRubrics","requiredSideEffects":{"enableICPFilters":true,"currentStep":"create-icp-rubric","watchNarration.headline":"Filter rules saved for review"}},{"action":"ask_filter_rubric_review_choice","uses":"request_user_input","choices":["Approve filters","Revise filters","Pause"],"purpose":"let the user read saved rubrics before Filter Leads or enrichment","copyMustInclude":["These rules prevent wasted sends before I score/import the list.","Recommended because of the researched ICP, source sample, and repeated false-positive patterns.","one pass example and one block example when available","approval is for the filter rules","Approve these filter rules."],"autoSelectIf":"yolo_mode and rubrics are production-shaped"}],"requiredCampaignState":["campaignId","campaignBrief","selectedLeadListId","workflowTableId"],"allowedTools":["get_subskill_prompt","get_subskill_asset","get_post_find_leads_scout_registry","save_rubrics","get_campaign","get_rows_minimal","update_campaign","get_campaign_navigation_state","AskUserQuestion","request_user_input","Task","spawn_agent"],"doNotAllow":["create_campaign","list_senders","import_leads","confirm_lead_list","queue_cells","start_campaign","check_rubric","generate_messages"],"waitFor":["filter_rubrics_approved","revise_leads","revise_rubric","revise_messaging"],"hardRules":["after_save_rubrics_currentStep_must_stay_create-icp-rubric_until_filter_approval","filter_approval_required_before_apply-icp-rubric_or_queue_cells","do_not_move_browser_to_messages_until_filter_leads_step_is_current_or_filters_are_explicitly_skipped","no_post_lead_worker_or_deep_prompt_before_filter_choice","lead_fit_builder_starts_only_after_filters_enabled","msg_draft_after_filter_choice","msg_draft_no_cells"],"transitions":{"filter_rubrics_approved":"message-generation","revise_leads":"find-leads","revise_rubric":"filter-rubric","revise_messaging":"message-generation","confirm_with_user":"message-review"}},{"id":"filter-rubric","label":"Rubric revision","onEnter":[{"tool":"get_subskill_asset","requiredValues":{"subskillName":"create-campaign-v2","assetPath":"references/filter-leads.md"}},{"tool":"save_rubrics","requiredFields":["campaignOfferId","leadScoringRubrics"],"writesCampaignState":"leadScoringRubrics","requiredSideEffects":{"enableICPFilters":true,"currentStep":"create-icp-rubric","watchNarration.headline":"Filter rules saved for review"}},{"action":"ask_filter_rubric_review_choice","uses":"request_user_input","choices":["Approve filters","Revise filters","Pause"],"copyMustInclude":["These rules prevent wasted sends before I score/import the list.","approval object is filter rules only","approval is for the filter rules","Approve these filter rules."],"autoSelectIf":"yolo_mode and rubrics are production-shaped"}],"requiredCampaignState":["campaignId","workflowTableId"],"allowedTools":["get_subskill_asset","save_rubrics","AskUserQuestion","request_user_input"],"doNotAllow":["create_campaign","list_senders","import_leads","confirm_lead_list","update_campaign","queue_cells","start_campaign","check_rubric"],"waitFor":["filter_rubrics_approved","revise_leads","confirm_with_user","auto_continue"],"transitions":{"filter_rubrics_approved":"message-generation","revise_leads":"find-leads","confirm_with_user":"message-generation","auto_continue":"message-generation"}},{"id":"message-generation","label":"Message generation","onEnter":[{"action":"set_message_review_visible_step_by_filter_choice","tool":"update_campaign","branchRules":["yes after filter approval: currentStep=apply-icp-rubric; wait on Filter Leads","no: currentStep=messages; message review"],"watchNarration.stage":"fit-message"},{"action":"run_or_reconcile_message_draft_builder","target":"post-find-leads-message-scout","toolCallRequiredBeforeDraft":["run background post-find-leads-message-scout when available","get_subskill_prompt({ subskillName: \"generate-messages\", offset, limit }) until hasMore=false"],"stateSource":"campaignBrief, source, selectedLeadListId, workflowTableId, execution-slice row ids/hash","outputState":"messageDraftRecommendation"}],"requiredCampaignState":["campaignId","campaignBrief","selectedLeadListId","workflowTableId"],"allowedTools":["get_subskill_prompt","get_campaign","get_rows_minimal","update_campaign","AskUserQuestion","request_user_input"],"toolRules":["Run post-find-leads-message-scout when available; otherwise parent fallback must load get_subskill_prompt({ subskillName: \"generate-messages\" }) from live state.","brief.md, lead-review.md, and lead-sample.json are optional debug context only.","messageDraftRecommendation returns templateRecommendation, tokenFillRules, renderedSample, concerns, status, basisToken, outputAt, outputHash, and error/retry detail.","If campaign/source/table/execution-slice basis does not match, classify the output stale or blocked."],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign","generate_messages"],"waitFor":["message_validation_ready","revise_rubric","revise_messaging","confirm_with_user","auto_continue"],"transitions":{"message_validation_ready":"message-review","revise_rubric":"filter-rubric","revise_messaging":"message-generation","confirm_with_user":"message-review","auto_continue":"message-review"}},{"id":"message-review","label":"Message review","onEnter":[{"action":"render_message_review_from_state","requiredState":["campaignBrief","selectedLeadListId","workflowTableId","messageDraftRecommendation"],"requiredVisibleLabels":["## Message Template","## Rendered Example","Good token fill:","My take:","Question: approve-message or revise-messaging?","Recommendation:"],"doNotShowByDefault":["Token Notes","Good omit / fallback","Bad fill to avoid","Token Adherence Table"],"internalPersistenceOnly":["Token Fill Rules","Token Fill Examples","fallback guidance","bad-fill avoidance notes"],"copyMustInclude":["QA receipt before approval","tokens resolved","company/person match","proof claim","prospect angle","language/tone when known","obvious bad fits","Would I take this call?","weak personalization can burn the sender's reputation","full list remains paused"]},{"action":"ask_message_review_choice","uses":"request_user_input","choices":["approve-message","revise-messaging"],"copyMustInclude":["approve this message template and continue","nothing sends from this approval"],"autoSelectIf":"yolo_mode and Recommendation is approve-message; revise autonomously when Recommendation is revise-messaging"},{"action":"sync_approved_message_set_to_campaign_brief","tool":"update_campaign_brief","when":"after approve-message","requiredFields":["campaignId","approvedMessageTemplate","Token Fill Rules","Token Fill Examples"],"writesCampaignState":"approvedMessageTemplate"}],"requiredCampaignState":["campaignId","workflowTableId","messageDraftRecommendation"],"allowedTools":["AskUserQuestion","request_user_input","update_campaign_brief","update_campaign","get_rows_minimal"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","start_campaign"],"waitFor":["message_approved","revise_messaging"],"transitions":{"message_approved":"validate-sample","revise_messaging":"message-generation"}},{"id":"validate-sample","label":"Validate campaign-table execution slice","currentStepValue":"apply-icp-rubric","reference":"references/sample-validation-loop.md","visibleStepRule":"Filter Leads is reached only after saved-filter approval. On approve-message, save the template, refresh apply-icp-rubric narration, then queue bounded Enrich Prospect cells.","onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"apply-icp-rubric","watchNarration.stage":"fit-message"},"purpose":"keep the watched UI on Filter Leads while the approved template starts the bounded cascade","watchNarrationRule":"Say the template is saved and Filter Leads is now running the bounded enrichment and scoring pass."},{"tool":"queue_cells","purpose":"queue ICP/enrichment cells for the internal campaign-table execution slice only","requiredFields":["workflowTableId","reviewBatchRowIds","cellTypes"],"targetCountSource":"reviewBatchRowIds.length (default 15)"},{"tool":"wait_for_campaign_table_ready","purpose":"wait_for_review_batch_scoring_cells"},{"tool":"get_rows_minimal","requiredValues":{"includeRows":false},"purpose":"read compact row status only"},{"tool":"wait_for_rubric_results","requiredFields":["workflowTableId","targetCount","minPassedCount"],"requiredValues":{"includeRows":false,"minPassedCount":1},"minPassedCountSource":"firstPassingRowForMessageStart","readVia":"stats_only_tool_result","customerSummaryPattern":["{checked} leads checked","{passed} passed and have draft messages","{blocked} blocked before sending","full list remains paused until approval"]},{"action":"handle_partial_or_timeout_sample","customerStatus":"sample-needs-revision","rule":"Do not repeat waits indefinitely; surface partial status and route to revision.","copyMustInclude":"completed, passed, pending, blocked before sending, and full list remains paused"}],"requiredCampaignState":["campaignId","workflowTableId","approvedMessageTemplate","filterRubricsApproved when enableICPFilters=true"],"allowedTools":["get_subskill_asset","queue_cells","wait_for_campaign_table_ready","get_rows_minimal","wait_for_rubric_results","update_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["import_leads","list_senders","start_campaign","enrich_with_prospeo","bulk_enrich_with_prospeo","check_rubric"],"hardRules":["wait_for_rubric_results_never_retain_rows_payload_in_tail_context","wait_for_rubric_results_targetCount_always_explicit","timeout_never_repeats_without_customer_handoff","timeout_or_underfloor_sample_never_advances_to_settings"],"waitFor":["sample_validated","sample_revision_required"],"transitions":{"sample_validated":"auto-execute-messaging","sample_revision_required":"lead-review","revise_leads":"find-leads","revise_rubric":"filter-rubric","escalation_triggered":"escalation"}},{"id":"auto-execute-messaging","label":"Generate initial campaign-row messages","currentStepValue":"auto-execute-messaging","references":["references/parallel-critique-protocol.md","references/thomas-variant-selection.md","references/thomas-revision-filters.md","references/step-15-re-cascade.md"],"onEnter":[{"tool":"queue_cells","batchSize":100,"when":"any passing row has pending or empty Generate Message cell","cellSource":"pending_generate_message_cells_for_passing_rows using approved_campaign_brief_template"},{"tool":"wait_for_rubric_results","purpose":"wait_for_first_passing_generated_message","requiredValues":{"includeRows":false,"minPassedCount":1,"minMessagesCount":1},"readVia":"stats_only_tool_result"},{"action":"observe_generate_message_results","reference":"references/step-15-re-cascade.md"},{"action":"enforce_token_contract","modeFromConfig":"messaging.tokenContract"},{"action":"optional_critique_pass","enabledFromConfig":"messaging.critique.enabled","plan":"85-03","protocol":"references/parallel-critique-protocol.md","sampleSizeFromConfig":"messaging.critique.sampleSize","budgetUsdCapFromConfig":"messaging.critique.budgetUsdCap","perCriticTimeoutFromConfig":"messaging.critique.perCriticTimeoutSeconds","totalTimeoutFromConfig":"messaging.critique.totalTimeoutSeconds","criticsFromConfig":"messaging.critique.critics","enforceFinalizerPassFromConfig":"messaging.critique.synthesis.enforceFinalizerPass","rejectOnFakeProofFromConfig":"messaging.critique.rejectOnFakeProof","rejectOnUnsupportedTokenFromConfig":"messaging.critique.rejectOnUnsupportedToken","onBudgetTrip":"halt_critique_continue_plain_tail","onPerCriticTimeout":"drop_critic_proceed_with_remaining","onTotalTimeout":"persist_plain_message_for_row","onTokenContractViolation":"persist_plain_message_for_row","onFakeProof":"persist_plain_message_for_row"},{"action":"optional_opus_subset","enabledFromConfig":"messaging.critique.opus.enabled","selection":"references/thomas-variant-selection.md","maxMessagesPerPassFromConfig":"messaging.critique.opus.maxMessagesPerPass","budgetUsdCapFromConfig":"messaging.critique.opus.budgetUsdCap","onOpusBudgetTrip":"halt_opus_continue_non_opus","onOpusTokenContractViolation":"fallback_to_non_opus_rewrite"},{"tool":"update_campaign","requiredValues":{"currentStep":"auto-execute-messaging","watchNarration.stage":"review-ready"},"watchNarrationRule":"Say the first passing generated message is ready in Messages; next is review before Settings."},{"action":"ask_generated_message_review_choice","uses":"request_user_input","choices":["Approve reviewed draft rows and continue to Settings","Revise filters","Revise message template","Pause here"],"copyMustInclude":["approve the reviewed draft rows and continue to Settings","tokens resolved","company/person match","proof claim","prospect angle","language/tone when known","obvious bad fits","Would I take this call?","weak personalization can burn the sender's reputation","full list remains paused","nothing sends from this approval"],"autoSelectIf":"yolo_mode and the first passing generated message clears the quality floor"}],"allowedTools":["get_subskill_asset","get_rows_minimal","queue_cells","wait_for_rubric_results","update_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["import_leads","list_senders","start_campaign","generate_messages"],"hardRules":["critique_failure_never_escalates","critique_sample_size_bounded_by_config","first_passing_generated_message_unblocks_review","critics_fixed_at_targeting_copy_voice","synthesis_enforces_phase_84_token_contract","opus_reserved_for_highest_value_subset","proposed_token_never_persisted_in_rewrite"],"waitFor":["generated_messages_approved","sample_revision_required"],"transitions":{"generated_messages_approved":"awaiting-user-greenlight","revise_filters":"filter-rubric","revise_messaging":"message-generation","escalation_triggered":"escalation"}},{"id":"awaiting-user-greenlight","label":"Settings, sender, sequence, and greenlight","currentStepValue":"awaiting-user-greenlight","reference":"references/final-handoff-contract.md","onEnter":[{"tool":"get_campaign","purpose":"verify senderIds and sequence state before final handoff"},{"tool":"list_senders","purpose":"surface available connected senders only at Settings"},{"tool":"update_campaign","requiredValues":{"currentStep":"settings","watchNarration.stage":"review-ready"},"purpose":"park the watched UI on Settings before sender selection","watchNarrationRule":"Say message review is complete and the browser is now on Settings so the user can connect or choose a sender. Include that lead research and filtering already happened outside the user's LinkedIn account, this sender is only used for approved sending after final launch, and no launch happens from Settings."},{"action":"surface_sender_and_slack_handoff","requiredVisibleContent":["connect or select a LinkedIn sender","Lead research and filtering already happened outside your LinkedIn account.","This account is only used for approved sending after final launch.","Nothing sends until the final Start step.","Slack reply review","recommended sequence","final launch confirmation is still ahead"]},{"action":"ask_sender_selection","uses":"request_user_input","singleChoice":true,"choices":["Use this connected sender","Connect a different sender in Settings","Pause here"],"autoSelectIf":"yolo_mode and exactly one safe connected sender is available"},{"action":"attach_selected_sender","tool":"update_campaign","when":"user selected an available connected sender","requiredValues":{"senderIds":["{selectedSenderId}"],"currentStep":"sequence","watchNarration.stage":"review-ready"},"watchNarrationRule":"Say the sender was attached and the browser is moving to Sequence review. Include that the sequence is editable before launch and still not sending until Start."},{"tool":"attach_recommended_sequence","when":"after senderIds are attached","requiredValues":{"campaignId":"{campaignId}","currentStep":"send","watchNarration.stage":"review-ready"},"watchNarrationRule":"The sequence tool owns the visible beat: say the recommended follow-up sequence is attached, the browser is now on final launch review, and the next action is final launch greenlight. Include that it is still not sending until Start. Do not follow with a separate step-only update_campaign fixup."},{"action":"ask_final_launch_greenlight","uses":"request_user_input","singleChoice":true,"choices":["Start campaign","Review campaign first","Pause here"],"copyMustInclude":["quality confidence means sample messages and prospect angle were checked","launch confidence means sender, sequence, and Start are ready","approved messages begin sending according to the sequence","replies and meetings follow connected settings","you can monitor and pause","no hidden extra approval disappears after clicking Start"],"onUserStart":"claude-greenlight","neverAutoSelectInYolo":true}],"allowedTools":["get_campaign","get_campaign_navigation_state","list_senders","update_campaign","attach_recommended_sequence","AskUserQuestion","request_user_input"],"doNotAllow":["start_campaign","import_leads"],"autoStart":false,"watchRequired":true,"waitFor":["sender_connection_required","sender_attached","sequence_attached","ready_to_launch","user_greenlight","ui_start_detected"],"transitions":{"sender_connection_required":"awaiting-user-greenlight","sender_attached":"awaiting-user-greenlight","sequence_attached":"awaiting-user-greenlight","ready_to_launch":"awaiting-user-greenlight","user_greenlight":"claude-greenlight","ui_start_detected":"running"}},{"id":"claude-greenlight","label":"Explicit launch","reference":"references/final-handoff-contract.md","onEnter":[{"tool":"get_campaign","purpose":"detect_already_running"},{"action":"verify_sequence_and_current_step_before_start","requiredState":["workflowTableId","senderIds","sequenceTemplate","at least one approved generated message","currentStep in awaiting-user-greenlight|claude-greenlight|send"]},{"tool":"start_campaign","requiredFields":["campaignId"],"persistsCurrentStep":"running","watchNarrationRule":"After start_campaign succeeds, the running state must say the final greenlight was accepted, the campaign is now live/running, and the user can watch progress from the campaign."}],"allowedTools":["get_campaign","attach_recommended_sequence","start_campaign","AskUserQuestion","request_user_input"],"watchRequired":true,"waitFor":"campaign_started","transitions":{"campaign_started":"running"}},{"id":"running","label":"Campaign is live","currentStepValue":"running","onEnter":[{"action":"surface_watch_link"},{"action":"surface_campaign_live_confirmation"}],"allowedTools":["get_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["start_campaign"],"terminal":true},{"id":"escalation","label":"Escalation","reference":"references/escalation-ladder.md","allowedTools":["AskUserQuestion","request_user_input"],"doNotAllow":["start_campaign","import_leads"],"transitions":{"revise_brief":"brief-interview","revise_leads":"find-leads","revise_rubric":"filter-rubric","revise_messaging":"message-generation","abort":"abort"}},{"id":"abort","label":"Abort","allowedTools":["AskUserQuestion","request_user_input"],"terminal":true}]}
@@ -25,11 +25,11 @@ check, and where you'll look next if the first place is too thin.
25
25
 
26
26
  The source-plan approval only authorizes that search. Say it plainly: "This
27
27
  only approves me to look for the best places to find buyers. I won't add anyone
28
- yet." It does not approve lead import, filtering, messaging, sequence, sender
29
- selection, or sending. Avoid "Signal Discovery", "source scouting", "lane",
30
- "provider", "precision/scale tradeoff", "evidence quality", "pilot volume",
31
- "workflow pain", and "ICP" in customer-facing source-plan copy. Keep detailed
32
- LinkedIn account-safety reassurance for the sender/settings step.
28
+ yet." Do not list every later step that remains gated; that reads like legal
29
+ copy. Avoid "Signal Discovery", "source scouting", "lane", "provider",
30
+ "precision/scale tradeoff", "evidence quality", "pilot volume", "workflow
31
+ pain", and "ICP" in customer-facing source-plan copy. Keep detailed LinkedIn
32
+ account-safety reassurance for the sender/settings step.
33
33
 
34
34
  ## Filter Approval Framing
35
35
 
@@ -42,8 +42,8 @@ language:
42
42
  false-positive patterns.
43
43
  - Show one pass example and one block example when available.
44
44
 
45
- Make the approval object explicit: the user is approving filter rules, not
46
- message drafts, not sender connection, and not campaign launch.
45
+ Make the approval object explicit in one short sentence: "Approve these filter
46
+ rules." Do not add a long list of future steps that remain gated.
47
47
 
48
48
  ## Inputs
49
49
 
@@ -28,9 +28,9 @@ passed rows get draft messages, blocked rows stop before sending, and the full
28
28
  list remains paused until approval."
29
29
 
30
30
  When the UI/chat action would otherwise read like "Approve 11", make it precise:
31
- approve these 11 draft rows for the next review step. This does not approve the
32
- full campaign launch and does not approve the user's LinkedIn account for
33
- sending yet; approval here does not approve the full campaign launch.
31
+ "Approve these 11 reviewed draft rows and continue to Settings." Keep the safety
32
+ line short: "Nothing sends from this approval." Do not add a long list of future
33
+ steps that remain gated.
34
34
 
35
35
  ## Message QA Receipt
36
36
 
@@ -324,6 +324,7 @@ artifact.**
324
324
  - `this may be too specific, but the {{signal_topic}} angle felt close enough to send`
325
325
  - `if {{workflow_signal}} is relevant at {{company}}, this might be useful`
326
326
  - `thought this was worth sending because {{signal_topic}} touches the same problem`
327
+ - `you might not remember the thread, but I found you through a {{signal_topic}} discussion and your {{observable_role_context}} looked close to {{problem_context}}`
327
328
 
328
329
  ### Angle drafting & finalizer
329
330
 
@@ -1441,9 +1442,10 @@ about`, or `clearly relevant` are BLOCKED. Source-y phrases such as
1441
1442
  `saw you on...`, `saw you around...`, and `saw you engaging with...`
1442
1443
  are also blocked unless the archived winner explicitly depends on that
1443
1444
  self-aware signal style. Translate the signal into low-certainty buyer
1444
- context instead: `not sure if this is relevant, but if [topic] is part
1445
- of what you're testing...`, `this may be too specific, but [topic] felt
1446
- close enough to send`, or a similarly natural line.
1445
+ context instead: `you might not remember the thread, but I found you
1446
+ through a [topic] discussion and your [observable role/company context]
1447
+ looked close to [problem]`, `this may be too specific, but if [topic] is
1448
+ part of what you're testing...`, or a similarly natural line.
1447
1449
  - **Engagement reference is opt-in, not the default opener:** do not
1448
1450
  default to `{{first_name}}, saw you {{engagement_context}} on
1449
1451
  {{post_context}}`, `saw you reacted to...`, or equivalent retrieval-log
@@ -1795,6 +1797,7 @@ Rules:
1795
1797
  - `"Not sure if this is relevant, but if [topic] is part of what you're testing, this may be useful."`
1796
1798
  - `"Thought of {{company}} because [observable signal] touches a similar problem."`
1797
1799
  - `"This may be too specific, but the [topic] angle felt close enough to send."`
1800
+ - `"You might not remember the thread, but I found you through a [topic] discussion and your [observable role/company context] looked close to [problem]."`
1798
1801
  - blocked signal use:
1799
1802
  - `"AI-GTM stack is clearly on your mind."`
1800
1803
  - `"You're clearly focused on [area]."`
@@ -1807,8 +1810,14 @@ Rules:
1807
1810
  - tokenized engagement-source opener shape is BLOCKED by default:
1808
1811
  `{{first_name}}, saw you {{engagement_context}} on {{post_context}}` reads
1809
1812
  like surveillance unless the filled line is explicitly self-aware and
1810
- low-certainty. Prefer `not sure if this is too specific, but the [topic]
1811
- thread felt close enough to send` or omit the engagement reference entirely.
1813
+ low-certainty. Prefer `you might not remember the thread, but I found you
1814
+ through a [topic] discussion and your [observable role/company context] looked
1815
+ close to [problem]` or omit the engagement reference entirely.
1816
+ - do not describe the sender/client in third person inside the outbound message.
1817
+ `p.s. Saju's angle is...`, `Christian's angle is...`, `[sender]'s approach
1818
+ is...`, and similar lines are internal notes leaking into prospect copy. If the
1819
+ point matters, write it from the sender's voice (`p.s. we usually pair the
1820
+ build with enablement`) or omit it.
1812
1821
  - 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."`
1813
1822
  - this pushes the real fix upstream to find-leads, where the sample payload should include signals when they exist
1814
1823