@sellable/mcp 0.1.335 → 0.1.337

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.
@@ -1 +1 @@
1
- {"version":"v2.1-compact","workflow":"create-campaign-v2","principle":"CampaignOffer/watch canonical: brief, source/import, filters/message, Settings, Start.","normalCustomerPath":"Use campaign state/MCP/watchNarration. Do not create, read, link, or surface local files. Print watch link once.","legacyCompatibility":{"validationSubskill":"create-campaign-v2-validation","tailSubskill":"create-campaign-v2-tail","rule":"Legacy diagnostics are opt-in, not active 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":"Watched currentStep switches need fresh watchNarration.","requiredFields":["stage","headline","visibleState","agentIntent","nextAction"],"copyMustInclude":["what just happened","visible page/state","next user action"],"appliesToTools":["create_campaign","update_campaign","attach_recommended_sequence","start_campaign"],"oneTimeWatchLinkPolicy":"must not print another watch-link handoff unless asked or recovering link."},"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"]},"yoloMode":{"triggerPhrases":["yolo","--yolo","mode=yolo","autopilot","use best guesses","use best estimates","answer for me","just run it","yolo autopilot"],"identityRequestOnlyWhenMissing":true,"operatorDirectionsRule":"Operator directions persist; newest conflicting direction wins.","setInteractionModeAfterCampaignCreate":"autonomous","autoSelectsPreLaunchChoices":["campaign focus","brief approval","source plan","Start 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 identity match"],"mustPauseFor":["missing LinkedIn profile URL or handle","missing credentials/data","ambiguous choice with no reasonable estimate","source/message/filter quality failure","final live launch confirmation"],"neverAutoStart":true},"steps":[{"id":"bootstrap","onEnter":[{"tool":"bootstrap_create_campaign","requiredValues":{"flowVersion":"v2"}},{"tool":"get_subskill_prompt","requiredValues":{"subskillName":"create-campaign-v2"}}],"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","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 or handle?\" Normalize handles to profile URLs; if not a profile, ask again before strategy questions.","requiresLinkedInProfileUrl":true,"doNotAcceptAsIdentityInput":["non-profile URL","company page","company/name-only input without a profile handle"],"acceptsLinkedInProfileHandle":true,"normalizeLinkedInProfileHandleToUrl":true},{"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 or handle"},{"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 should we pitch to prospects first?","options":["Use Sellable's researched recommendation","Use my current pitch","Shape the pitch together"],"copyMustInclude":["research basis","public LinkedIn research may be stale","recommendation is editable","pitch to prospects"],"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":"render_supplied_setup_receipt_before_brief_when_setup_questions_skip","when":"any setup question is skipped because the user already supplied or yolo mode inferred identity, target, offer, proof, or source","output":"normal chat receipt before the campaign brief or watch-link handoff","copyMustInclude":["Accepted LinkedIn input: normalized to the required LinkedIn profile URL.","Offer path: supplied current offer or Sellable's researched recommendation; you can replace it with your current offer."],"copyMustNotInclude":["Campaign Identity"]},{"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":"exact create_campaign.watchUrl; direct /campaign-builder/{campaignId}?mode={claude|codex} URL with workspaceId and token","copyMustInclude":["WATCH CODEX BUILD","Open live campaign builder","Keep this chat open.","approval questions here"],"immediateNextMainChatLine":"Ask for brief approval now. After approval, say: \"Brief approved. 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},"copyMustAvoid":["bare /campaign-builder/{campaignId} URL","derived watch URL","second watch-link handoff","shell open command","Next, we'll choose where to find buyers"],"oneTimeOnly":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","onEnter":[{"action":"render_brief_inline","minimumVisibleDetail":"campaign direction, buyer, offer, proof, source plan, safety gates","copyMustInclude":["This brief is based on Sellable's research and your answers.","If your site or LinkedIn is stale","Does this brief look right, and how should Sellable continue?"],"copyMustNotInclude":["quoted first-message copy","Message Angle as final proof","This approval covers","does not approve adding people","does not approve scraping posts","selecting a sender","attaching a sequence","Campaign Identity","what should this campaign sell first","sell first","[from you]","[from LinkedIn]","[from website]","[from case study]","[Sellable recommendation]"],"messageHintRule":"If any message-shape hint remains, keep it as non-final bullets and say real examples come after leads are found and filtered.","approvalBoundaryRule":"Keep this gate positive and short: ask approve/revise, then move to choosing where to find buyers.","sectionLabelRule":"Use ## Sender and Company for the person/company context; never render ## Campaign Identity.","skipIf":"the full brief was already rendered in the current shell-creation handoff before create_campaign returned","renderOnceRule":"Brief visible once before approval. If shown before shell creation, do not repeat after; append one watch-link handoff, then ask.","copyMustAvoid":["duplicate brief render after shell creation","second Watch link:"]},{"action":"ask_brief_choice","uses":"request_user_input","choices":["Approve brief + activate YOLO mode (Recommended)","Approve brief + build campaign with AI, step by step","Revise brief"],"skipIf":"yolo_mode; auto_continue after rendering assumptions unless brief quality floor fails","question":"Does this brief look right, and how should Sellable continue?","autonomousChoice":"Approve brief + activate YOLO mode (Recommended)","choiceDescriptions":{"Approve brief + activate YOLO mode (Recommended)":"Sellable will auto-decide the remaining setup choices with best guesses, including sources, filters, and messaging. It still stops before final launch.","Approve brief + build campaign with AI, step by step":"Approve this direction, then work with the AI through each major setup decision before it continues.","Revise brief":"Change the target, offer, proof, or campaign direction before continuing."}}],"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","sourceSelectionFunnel":{"preScoutRecommendationGate":{"required":true,"mustHappenBefore":["get_provider_prompt","search_signals","search_sales_nav","search_prospeo_companies","confirm_prospeo_company_accounts","search_prospeo","fetch_post_engagers"],"show":["buyer groups or places we could check","best place to start","where the right buyers are already talking","what signs the next search will check","where to look next if the first place is too thin","what approval authorizes"],"approvalAuthorizes":"best places to find buyers; no one added yet","explanationMustInclude":["why that place fits this campaign","enough likely prospects","what counts as a good sign","I won't add anyone yet"],"yoloMode":{"autoApproveRecommendedLane":true,"mustShowAssumedChoice":true,"pauseIfConfidenceLow":true},"customerLanguage":{"readability":"grade-5","requiredHeading":"Find Buyers Plan","prefer":["people to check","prospects"],"avoid":["lane","precision/scale tradeoff","evidence quality","workflow pain","ICP"],"termRule":{"buyers":"target market","peopleToCheck":"raw reactions/comments before fit is known","prospects":"likely usable people after fit","leads":"campaign rows"}},"questionOrder":"update_campaign to pick-provider; render Find Buyers Plan without repeating the watch link; never ask first; exactly one structured source-plan question total.","approvalFreshnessRule":"Do not reuse brief approval; continue exact earlier source-plan choice instead of asking a second identical question.","copyMustAvoid":["Watch link:","watch-link handoff"]},"defaultWhenSourceUnspecified":["signal-discovery","sales-nav-recent-active","sales-nav-general","prospeo"],"parallelAllowedOnlyWhen":["user explicitly requested source comparison"]},"onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"pick-provider","watchNarration.stage":"find-leads","watchNarration.headline":"Review where to find buyers","watchNarration.visibleState":"Source selection is visible before lead finding.","watchNarration.agentIntent":"Codex is explaining where to look first and fallback.","watchNarration.nextAction":"Approve where to look first or choose another place","watchNarration.safety":"Only deciding where to look. No one is added yet."}},{"action":"render_find_buyers_plan_inline","oneShot":true,"requiredPrecondition":"currentStep=pick-provider has been saved with update_campaign","mustHappenAfter":["update_campaign currentStep=pick-provider"],"mustHappenBefore":["ask_find_buyers_plan_choice","get_provider_prompt","search_signals","search_sales_nav","search_prospeo_companies","confirm_prospeo_company_accounts","search_prospeo","fetch_post_engagers"],"output":"normal chat text before any request_user_input approval panel","requiredHeading":"Find Buyers Plan","requiredInlineFields":["buyer groups or places for this campaign","best place to start","why that place fits this campaign","where to look next if thin","what approval authorizes"],"copyMustInclude":["choose where to find buyers","I won't add anyone yet"],"copyMustAvoid":["lane","source scouting","provider","precision/scale tradeoff","evidence quality","pilot volume","ICP","workflow pain","lead-source scouting","not importing leads","Watch link:","campaign-builder URL","repeat the watch URL","watch-link handoff"],"approvalBoundary":"Approves where to look; no one added yet.","linkPolicy":"Do not include another watch link."},{"action":"ask_find_buyers_plan_choice","uses":"request_user_input","oneShot":true,"requiredPrecondition":"visible plan rendered; no earlier approval can satisfy this unless exact visible source choice exists; do not ask this if that exact earlier source choice exists","skipIf":"earlier source-plan question already captured exact visible source choice, post-plan provider, or yolo choice","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","copyMustInclude":["Approve this plan for where to find buyers?","Start with LinkedIn posts"],"mustNotHappenBefore":["render_find_buyers_plan_inline"],"approvalStateRule":"Never ask a second identical source-plan question; set source_lane_approved only after visible plan, never from brief approval/generic/pre-plan state."},{"action":"persist_provider_search_step_before_search","tool":"update_campaign","requiredPrecondition":"source_lane_approved set after the visible Find Buyers Plan approval question","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_companies","confirm_prospeo_company_accounts","search_prospeo","fetch_post_engagers"]},{"action":"run_parent_thread_source_funnel","requiredPrecondition":"source_lane_approved after visible Find Buyers Plan approval","mode":"parent_thread_inline_sequential","sourceAgents":"forbidden in normal create-campaign","loadsOnlyActiveProviderPrompt":true,"defaultOrder":["signal-discovery","sales-nav-recent-active","sales-nav-general","prospeo"],"stopOnFirstViableUnlessComparisonRequested":true}],"requiredCampaignState":["campaignId","campaignBrief","currentStep"],"allowedTools":["get_provider_prompt","lookup_sales_nav_filter","search_sales_nav","search_prospeo_companies","confirm_prospeo_company_accounts","search_prospeo","search_signals","select_promising_posts","fetch_post_engagers","fetch_company","fetch_linkedin_profile","load_csv_dnc_entries","load_csv_linkedin_leads","load_csv_domains","get_rows_minimal","update_campaign","AskUserQuestion","request_user_input","get_campaign_navigation_state"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign","Task","spawn_agent"],"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":"Start Import approval","onEnter":[{"action":"show_source_decision_card","requiredInlineFields":["primary source and exact filters/recipe","Start Import 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 happens after Start Import"],"copyMustAvoid":["lead-source scouting","source scouting","headline-fit","engagers needed","execution slice","ICP","good buyers","real buyers","This approval covers","It does not approve","does not approve filters","filters, messages, sender selection","sender selection, sequence, or sending","Watch link:","campaign-builder URL","repeat the watch URL"],"approvalBoundaryRule":"Use positive Start Import copy only: after approval build source list, add to campaign, review first 15 leads; never list future non-approvals.","linkPolicy":"Do not include another watch link in Source Recommendation; describe the Start Import decision only."},{"action":"ask_source_review_choice","uses":"request_user_input","choices":["Approve scraping N recommended LinkedIn posts","Start Import for the approved source list","Revise source","Pause here"],"approvalChoiceLabelsByProvider":{"signal-discovery":"Approve scraping {scrapePostCount} recommended LinkedIn posts?","sales-nav":"Start Import for the approved Sales Nav source list","prospeo":"Start Import for the approved Prospeo source list"},"postApprovalContract":{"singleUseApproval":true,"doNotRepeatAfterApproval":["Source Recommendation","show_source_decision_card","ask_source_review_choice"],"requiredNextActionAfterApproval":"get_provider_prompt then import_leads","signalDiscoveryNextTool":"get_provider_prompt then import_leads"},"autoSelectIf":"yolo_mode and projected usable pool clears the source quality floor","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]}],"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","currentStepValue":"auto-execute-leads","reference":"references/step-13-import-leads.md","onEnter":[{"tool":"get_subskill_prompt","requiredValues":{"subskillName":"create-campaign-v2-tail"}},{"tool":"get_provider_prompt"},{"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","repeatUntil":"ready_true_or_cancelled_or_import_failed","requiredValues":{"requireComplete":true},"onImportStillRunning":"re-run wait_for_lead_list_ready; do not call confirm_lead_list just because rows exist","partialOverrideRule":"Only if the user explicitly asks to keep going early may the next confirm_lead_list call pass allowPartialSourceList: true."},{"tool":"confirm_lead_list","requiredFields":["campaignOfferId","selectedLeadListId","reviewBatchLimit"],"requiredValues":{"reviewBatchLimit":15},"capture":["workflowTableId","reviewBatchRowIds"],"requiredPrecondition":"wait_for_lead_list_ready returned ready:true, unless the user explicitly asked to keep going early with a partial list","partialOverrideField":"allowPartialSourceList:true only after explicit user early-continue instruction","mustNotRunWhen":["wait_for_lead_list_ready reason=import_still_running and no explicit early-continue instruction","wait_for_lead_list_ready reason=cancelled","wait_for_lead_list_ready reason=import_failed","missing import job metadata"]},{"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","maxCustomerCopyLines":4,"copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"linkPolicy":"Ask add filters vs skip filters without repeating the watch link.","purpose":"ask filter choice immediately"}],"requiredCampaignState":["campaignId","providerSearchAssociation","selectedLeadListId"],"allowedTools":["get_provider_prompt","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"},"hardRules":["import_leads_then_repeated_wait_for_lead_list_ready_then_confirm_lead_list_then_wait_for_campaign_table_ready","partial_source_rows_do_not_unblock_confirm_lead_list_without_explicit_user_early_continue","cancelled_or_failed_source_import_stops_before_campaign_table_copy"]},{"id":"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","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"copyMustInclude":["source rows are in the campaign","use filters while Message Drafting runs or skip filters"]}],"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_prospect_setup_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":"prospect-setup","filters_skipped":"prospect-setup","revise_leads":"find-leads"}},{"id":"prospect-setup","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":"Filter Rules is visible while Codex drafts/saves filters.","watchNarration.nextAction":"Review saved filter rules"},"mustRunBefore":["get_post_find_leads_scout_registry","launch_message_drafting_after_filter_choice","load_filter_reference_in_parent","save_rubrics","ask_filter_rubric_review_choice"]},{"tool":"get_post_find_leads_scout_registry","returns":["post-find-leads-message-scout"],"rule":"normal post-import registry exposes only Message Drafting; filters are parent-thread MCP work","mustRunBefore":["launch_message_drafting_after_filter_choice","get_subskill_asset:references/filter-leads.md","save_rubrics","ask_filter_rubric_review_choice"],"registryOnlyIsNotLaunch":true},{"action":"launch_message_drafting_after_filter_choice","mode":"background_agent_when_host_supports_subagents","target":"post-find-leads-message-scout","when":"filters_enabled or filters_skipped after filter-choice answer","doesNotQueueCells":true,"customerNarration":"Message Drafting is preparing.","inputs":["campaignId","workflowTableId","brief/source summary","3-5 sample workflow-table rows","optional campaignName/selectedLeadListId/filterChoice"],"forbiddenSiblings":["source/filter workers"],"handoffCompression":"lean_message_drafting_handoff_no_hashes_no_counts_no_full_row_data","requiredConcreteToolCall":"Task or spawn_agent when host supports background agents","registryOnlyIsNotLaunch":true,"mustRunBefore":["get_subskill_asset:references/filter-leads.md","load_filter_reference_in_parent","save_rubrics","ask_filter_rubric_review_choice"],"yoloPermissionRule":"do not ask the user for worker permission in YOLO.","startProof":"Message Drafting counts as started only after Task/spawn_agent.","noBackgroundFallback":"Start the same full message branch inline before filter reference or block."},{"action":"continue_after_drafting","when":"filters_skipped","transition":"filters_skipped_message_started"},{"tool":"get_subskill_asset","action":"load_filter_reference_in_parent","when":"filters_enabled","requiredValues":{"subskillName":"create-campaign-v2","assetPath":"references/filter-leads.md"},"rule":"Parent thread uses this reference to draft production rubrics; do not spawn a filter worker."},{"tool":"save_rubrics","when":"filters_enabled","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":["Filter rules saved for review","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 saved filter rules","Approve these filter rules."],"autoSelectIf":"yolo_mode and parent saved production-shaped rubrics","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"requiredPrecondition":"save_rubrics succeeded or active campaign rubrics verified"}],"requiredCampaignState":["campaignId","campaignBrief","selectedLeadListId","workflowTableId"],"allowedTools":["get_post_find_leads_scout_registry","get_subskill_asset","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","filters_skipped_message_started"],"hardRules":["after_save_rubrics_currentStep_must_stay_create-icp-rubric_until_filter_approval","filter_approval_required_before_apply-icp-rubric_or_queue_campaign_cells","do_not_move_browser_to_messages_until_filter_leads_step_is_current_or_filters_are_explicitly_skipped","no_prospect_setup_worker_or_deep_prompt_before_filter_choice","message_drafting_after_filter_choice","message_drafting_no_cells","only_message_drafting_may_spawn_background_agent","filters_are_parent_thread_mcp_work","no_post_find_leads_filter_scout_in_normal_path","registry_call_is_not_message_drafting_launch","yolo_must_not_ask_permission_for_message_drafting_worker","message_drafting_must_start_before_filter_reference_or_save_rubrics","if_background_agent_unavailable_start_full_message_branch_inline_before_filters_or_block","message_drafting_start_does_not_advance_filter_path"],"transitions":{"filter_rubrics_approved":"message-generation","revise_leads":"find-leads","revise_rubric":"filter-rubric","revise_messaging":"message-generation","confirm_with_user":"message-review","filters_skipped_message_started":"message-generation"}},{"id":"filter-rubric","onEnter":[{"tool":"get_subskill_asset","requiredValues":{"subskillName":"create-campaign-v2","assetPath":"references/filter-leads.md"}},{"action":"observed-row-grounding","uses":["get_rows_minimal","get_rows","enrich_with_prospeo"],"requiredBefore":"save_rubrics","contract":["Call get_rows_minimal before drafting filters.","Call get_rows({ tableId, rowIds }) for row/enrichment sample; rowIds must be a JSON array, not a comma-delimited string.","Use multiple visible rows for repeated false positives, broad enterprise sellers, noisy titles, agencies/vendors, geography, and budget gaps.","Use one direct enrichment sample via enrich_with_prospeo if rows are thin; set enrichMobile: false.","On direct enrichment failure, no credits, provider error, or no match, do not retry; continue with uncertainty or block.","If no rows, do not enrich or save row-grounded filters; ask/import rows or use brief/source with uncertainty.","If zero enriched fields, separate raw row fields from unavailable enrichment; do not pretend enrichment-backed filters are observed.","Stop before save_rubrics on stale workflowTableId/source/campaignId/row ids.","Fail generic sales/BD/partnerships unless target/current evidence proves fit and budget path.","No standalone current_role_* safety; fold into keep/exclude or engagement_only_or_stale_fit_exclusion."]},{"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","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]}],"requiredCampaignState":["campaignId","workflowTableId"],"allowedTools":["get_subskill_asset","get_rows_minimal","get_rows","enrich_with_prospeo","save_rubrics","AskUserQuestion","request_user_input"],"doNotAllow":["create_campaign","list_senders","import_leads","confirm_lead_list","update_campaign","queue_cells","start_campaign","check_rubric","queue_campaign_cells","bulk_enrich_with_prospeo"],"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","onEnter":[{"action":"set_message_review_visible_step_by_filter_choice","tool":"update_campaign","watchNarration.stage":"fit-message","requiredValues":{"currentStep":"apply-icp-rubric","watchNarration.stage":"fit-message","watchNarration.headline":"Filters saved + waiting for message approval"},"watchNarrationRule":"After filter approval, show Filter Leads; do not queue enrichment/filter/message cells before approve-message.","mustRunBefore":"run_or_reconcile_message_draft_builder","failureRule":"currentStep=apply-icp-rubric"},{"action":"run_or_reconcile_message_draft_builder","target":"post-find-leads-message-scout","toolCallRequiredBeforeDraft":["Task/spawn_agent or inline fallback before parent drafting","generic gpt-5.5 xhigh Message Drafting fallback","lean handoff: campaignId, workflowTableId, brief, source rule, 3-5 rows","no copied counts, hashes, full row ids, broad row data, or artifacts","branch loads current brief/context, full generate-messages prompt/assets","return labeled Markdown: template, token rules, sample, status, recommendation, validation, hash, retry","hide fallback sample, risk notes, and qaReceipt on happy path","inline fallback=parent-thread-fallback; same gates"],"stateSource":"live campaign/table plus sample rows","outputState":"messageDraftRecommendation with internal validation passed","revisionMode":{"when":"revise_messaging, message QA request, or latest user message requests template changes before approve-message","route":"send feedback/QA/rewrite request to post-find-leads-message-scout or generic gpt-5.5 xhigh Message Drafting branch","requiredInputs":["latest user feedback","current messageDraftRecommendation and basisToken/outputHash","lean campaign/table basis and brief summary; branch reloads live state"],"forbiddenParentActions":["rewrite template in parent","QA template in parent from memory","update_campaign_brief before approve-message"],"output":"revised messageDraftRecommendation rendered before request_user_input"},"onlyMessageBackgroundAgent":true,"forbiddenSiblingAgents":["source-scout-*","any filter background worker"],"handoffCompression":"lean_message_handoff","finalGateRequiredBeforeReady":"Load create-campaign-v2-validation before ready."}],"requiredCampaignState":["campaignId","campaignBrief","selectedLeadListId","workflowTableId"],"allowedTools":["get_subskill_prompt","get_campaign","get_rows_minimal","update_campaign","Task","spawn_agent"],"toolRules":["message_drafting_agent_first_no_silent_parent_fallback; yolo counts","on_filters_enabled_path_parent_must_not_enter_message_review_until_save_rubrics_success_and_filter_approval","brief.md, lead-review.md, and lead-sample.json are optional debug context only.","messageDraftRecommendation returns template, token rules, rendered sample, status, recommendation, validation, hash, retry.","messageDraftRecommendation hides fallback/risk/qaReceipt in the happy path.","If campaign/table/sample basis does not match, classify the output stale or blocked.","message_revision_feedback_routes_to_message_drafting_agent_not_parent","message_qa_routes_to_message_drafting_agent_not_parent","message_drafting_loads_full_generate_messages_prompt_all_chunks","message_drafting_loads_all_reference_assets_via_get_subskill_asset","message_drafting_loads_create_campaign_v2_validation_prompt_before_return","message_drafting_handoff_uses_lean_basis_no_hashes_counts_or_full_rows","message_drafting_loads_current_campaign_brief_before_drafting","parent_may_load_generate_messages_only_for_explicitly_approved_inline_fallback","before return branch loads create-campaign-v2-validation prompt and runs internal validation","pre_approval_step_filter_leads"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign","generate_messages","AskUserQuestion","request_user_input"],"waitFor":["message_validation_ready","revise_rubric","revise_messaging"],"transitions":{"message_validation_ready":"message-review","revise_rubric":"filter-rubric","revise_messaging":"message-generation"},"revisionLoop":{"trigger":"user gives copy feedback, asks for QA/update, or chooses revise-messaging","required":["route latest user feedback or QA request to Message Drafting with current recommendation and live campaign/table state","produce a new messageDraftRecommendation with revisionNotes or validationStatus","render revised ## Message Template, ## Rendered Example, and What changed before asking approval"],"blocked":["asking whether an unseen new version is better","reusing the old template after acknowledging feedback","rewriting the template in the parent thread","update_campaign_brief before approve-message","request_user_input or AskUserQuestion during message-generation","QAing the template in the parent thread"],"outputState":"messageDraftRecommendation"},"hardRules":["message_revision_must_render_new_template_before_approval_question","message_revision_saves_only_after_approve_message","message_generation_must_not_call_request_user_input","message_generation_must_transition_to_message_review_only_after_renderable_draft_state","message_drafting_agent_first_no_silent_parent_fallback","message_revision_routes_to_message_drafting_agent","message_qa_routes_to_message_drafting_agent","filter_path_requires_saved_filters_before_message_review","only_message_drafting_may_spawn_background_agent","no_queue_before_template_approval"],"currentStepValue":"apply-icp-rubric"},{"id":"message-review","onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"apply-icp-rubric","watchNarration.stage":"fit-message"},"watchNarrationRule":"Before template approval, keep browser on Filter Leads.","mustRunBefore":"render_message_review_from_state","failureRule":"do not ask for message approval until Filter Leads shows and cells unqueued."},{"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":["Rendered fallback sample","Concerns","QA receipt","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","validation notes","QA details"],"copyMustInclude":["one recommended template","one rendered sample","token rules and fallbacks","full list remains paused"],"copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"revisionRenderRule":"After feedback, route feedback to Message Drafting; show revised template/example; never ask if an unseen version is better.","parentMustNot":["rewrite template from memory","invent validation summary without Message Drafting output","render qaReceipt, risk notes, or renderedFallbackSample on the normal happy path"]},{"action":"ask_message_review_choice","uses":"request_user_input","choices":["approve-message","revise-messaging"],"copyMustInclude":["approve this message template and continue","template approval only locks the draft direction; final Start still controls sending"],"autoSelectIf":"yolo_mode and Recommendation is approve-message; revise autonomously when Recommendation is revise-messaging","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"requiredPrecondition":"current or revised template and rendered example are visible in this turn","revisionPrecondition":"after revise_messaging, revised template is visible before this question"},{"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","revisionApprovalRule":"If the user requested revisions, write only the latest Message Drafting-approved revised template and token rules after approve-message.","forbiddenBefore":"approve-message"}],"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"},"currentStepValue":"apply-icp-rubric"},{"id":"validate-sample","currentStepValue":"apply-icp-rubric","reference":"references/sample-validation-loop.md","visibleStepRule":"After saved-filter approval and approve-message, queue bounded Enrich Prospect cells.","onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"apply-icp-rubric","watchNarration.stage":"fit-message"},"watchNarrationRule":"Template saved; Filter Leads runs bounded enrichment/scoring."},{"tool":"queue_campaign_cells","requiredFields":["workflowTableId","columnRole","rowSelector"],"requiredValues":{"columnRole":"enrich","rowSelector":{"type":"reviewBatch"},"forceRerun":false},"targetCountSource":"reviewBatch.rowCount default 15"},{"tool":"wait_for_campaign_processing","requiredFields":["workflowTableId","minPassedCount"],"requiredValues":{"minPassedCount":1},"readVia":"stats_only_tool_result","timeoutGuidance":"On timeout, use partial diagnostics; do not repeat identical waits.","customerSummaryPattern":["{checked} leads checked","{passed} passed fit scoring","{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_campaign_cells","select_campaign_cells","get_campaign_table_schema","wait_for_campaign_processing","update_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["import_leads","list_senders","start_campaign","enrich_with_prospeo","bulk_enrich_with_prospeo","check_rubric"],"hardRules":["campaign_processing_waits_are_stats_only_by_default","queue_review_batch_by_selector_never_fetch_rows_for_cell_ids","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","currentStepValue":"auto-execute-messaging","references":["references/parallel-critique-protocol.md","references/thomas-variant-selection.md","references/sellable-cleanup-rules.md","references/step-15-re-cascade.md"],"onEnter":[{"tool":"queue_campaign_cells","batchSize":100,"when":"any passing row has pending, empty, or stale Generate Message cell","requiredFields":["workflowTableId","columnRole","rowSelector"],"requiredValues":{"columnRole":"generateMessage","rowSelector":{"type":"needsGeneratedMessage"},"forceRerun":false},"cellSource":"selector-engine needsGeneratedMessage rows using approved campaign brief template"},{"tool":"wait_for_campaign_processing","purpose":"wait_for_first_current_revision_generated_message","requiredValues":{"minGeneratedMessages":1,"templateRevision":"current"},"readVia":"stats_only_tool_result","invariant":"A generated message implies the pass gate; stale or wrong-revision messages are excluded from readiness."},{"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","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","this approves reviewed draft rows for setup; final Start still controls sending"],"autoSelectIf":"yolo_mode and the first passing generated message clears the quality floor","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]}],"allowedTools":["get_subskill_asset","get_campaign_table_schema","select_campaign_cells","queue_campaign_cells","wait_for_campaign_processing","revise_message_template_and_rerun","update_campaign","AskUserQuestion","request_user_input","update_cell"],"doNotAllow":["import_leads","list_senders","start_campaign","generate_messages"],"hardRules":["generated_message_count_excludes_stale_or_wrong_revision_messages","message_template_revision_uses_brief_update_then_generate_message_rerun","do_not_overwrite_generated_message_cells_directly","critique_failure_never_escalates","critique_sample_size_bounded_by_config","first_passing_generated_message_unblocks_review","critics_fixed_at_targeting_copy_voice","synthesis_enforces_message_token_contract","opus_reserved_for_highest_value_subset","proposed_token_never_persisted_in_rewrite","approve_reviewed_rows_via_semantic_approved_selector_not_get_rows_approveCellId"],"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","currentStepValue":"awaiting-user-greenlight","reference":"references/final-handoff-contract.md","onEnter":[{"tool":"start_campaign_message_preparation","requiredValues":{"targetPreparedMessages":"{requestedMessageCount}","approvalMode":"{scheduleOrApproveIntent ? 'approve' : 'mark_ready'}"},"intentMapping":{"scheduleSends":"approve the exact requested send count"},"when":"explicit_count_or_schedule","batchStrategy":"max100_serial","rowBudgetStrategy":"sample100_cap300"},{"tool":"get_campaign_message_preparation_status","copyMustInclude":["preparation job status","checked rows","target","stop reason"],"when":"prep_job_started"},{"tool":"get_campaign"},{"tool":"list_senders","purpose":"identity proof at Settings"},{"tool":"update_campaign","requiredValues":{"currentStep":"settings","watchNarration.stage":"review-ready"},"watchNarrationRule":"Say message review is complete, Settings is open, lead research/filtering happened outside LinkedIn, and nothing sends until Start."},{"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"],"copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]},{"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 one exact identity match","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"noAutoSelectIf":"identity proof is missing; ask"},{"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 app is moving to Sequence review; sequence remains editable and nothing sends until Start."},{"tool":"attach_recommended_sequence","when":"after senderIds are attached","requiredValues":{"campaignId":"{campaignId}","currentStep":"send","watchNarration.stage":"review-ready"},"watchNarrationRule":"Say the recommended follow-up sequence is attached, final launch review is open, and nothing sends until Start."},{"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,"copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]}],"allowedTools":["cancel_campaign_message_preparation","get_campaign_message_preparation_status","start_campaign_message_preparation","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","reference":"references/final-handoff-contract.md","onEnter":[{"tool":"get_campaign"},{"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"],"boundedLaunchRule":"preparation job approved X; no broad approve-all."},{"tool":"start_campaign","requiredFields":["campaignId"],"persistsCurrentStep":"running","watchNarrationRule":"After start_campaign succeeds, say final greenlight was accepted, campaign is live/running, and progress can be watched."}],"allowedTools":["get_campaign","attach_recommended_sequence","start_campaign","AskUserQuestion","request_user_input"],"watchRequired":true,"waitFor":"campaign_started","transitions":{"campaign_started":"running"}},{"id":"running","currentStepValue":"running","onEnter":[{"action":"surface_campaign_live_confirmation_without_watch_link","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]}],"allowedTools":["get_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["start_campaign"],"terminal":true},{"id":"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","allowedTools":["AskUserQuestion","request_user_input"],"terminal":true}]}
1
+ {"version":"v2.1-compact","workflow":"create-campaign-v2","principle":"CampaignOffer/watch canonical: brief, source/import, filters/message, Settings, Start.","normalCustomerPath":"Use campaign state/MCP/watchNarration. Do not create, read, link, or surface local files. Print watch link once.","legacyCompatibility":{"validationSubskill":"create-campaign-v2-validation","tailSubskill":"create-campaign-v2-tail","rule":"Legacy diagnostics are opt-in, not active 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":"Watched currentStep switches need fresh watchNarration.","requiredFields":["stage","headline","visibleState","agentIntent","nextAction"],"copyMustInclude":["what just happened","visible page/state","next user action"],"appliesToTools":["create_campaign","update_campaign","attach_recommended_sequence","start_campaign"],"oneTimeWatchLinkPolicy":"must not print another watch-link handoff unless asked or recovering link."},"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"]},"yoloMode":{"triggerPhrases":["yolo","--yolo","mode=yolo","autopilot","use best guesses","use best estimates","answer for me","just run it","yolo autopilot"],"identityRequestOnlyWhenMissing":true,"operatorDirectionsRule":"Operator directions persist; newest conflicting direction wins.","setInteractionModeAfterCampaignCreate":"autonomous","autoSelectsPreLaunchChoices":["campaign focus","brief approval","source plan","Start 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 identity match"],"mustPauseFor":["missing LinkedIn profile URL or handle","missing credentials/data","ambiguous choice with no reasonable estimate","source/message/filter quality failure","final live launch confirmation"],"neverAutoStart":true},"steps":[{"id":"bootstrap","onEnter":[{"tool":"bootstrap_create_campaign","requiredValues":{"flowVersion":"v2"}},{"tool":"get_subskill_prompt","requiredValues":{"subskillName":"create-campaign-v2"}}],"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","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 or handle?\" Normalize handles to profile URLs; if not a profile, ask again before strategy questions.","requiresLinkedInProfileUrl":true,"doNotAcceptAsIdentityInput":["non-profile URL","company page","company/name-only input without a profile handle"],"acceptsLinkedInProfileHandle":true,"normalizeLinkedInProfileHandleToUrl":true},{"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 or handle"},{"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 should we pitch to prospects first?","options":["Use Sellable's researched recommendation","Use my current pitch","Shape the pitch together"],"copyMustInclude":["research basis","public LinkedIn research may be stale","recommendation is editable","pitch to prospects"],"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":"render_supplied_setup_receipt_before_brief_when_setup_questions_skip","when":"any setup question is skipped because the user already supplied or yolo mode inferred identity, target, offer, proof, or source","output":"normal chat receipt before the campaign brief or watch-link handoff","copyMustInclude":["Accepted LinkedIn input: normalized to the required LinkedIn profile URL.","Offer path: supplied current offer or Sellable's researched recommendation; you can replace it with your current offer."],"copyMustNotInclude":["Campaign Identity"]},{"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":"exact create_campaign.watchUrl; direct /campaign-builder/{campaignId}?mode={claude|codex} URL with workspaceId and token","copyMustInclude":["WATCH CODEX BUILD","Open live campaign builder","Keep this chat open.","approval questions here"],"immediateNextMainChatLine":"Ask for brief approval now. After approval, say: \"Brief approved. 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},"copyMustAvoid":["bare /campaign-builder/{campaignId} URL","derived watch URL","second watch-link handoff","shell open command","Next, we'll choose where to find buyers"],"oneTimeOnly":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","onEnter":[{"action":"render_brief_inline","minimumVisibleDetail":"campaign direction, buyer, offer, proof, source plan, safety gates","copyMustInclude":["This brief is based on Sellable's research and your answers.","If your site or LinkedIn is stale","Does this brief look right, and how should Sellable continue?"],"copyMustNotInclude":["quoted first-message copy","Message Angle as final proof","This approval covers","does not approve adding people","does not approve scraping posts","selecting a sender","attaching a sequence","Campaign Identity","what should this campaign sell first","sell first","[from you]","[from LinkedIn]","[from website]","[from case study]","[Sellable recommendation]"],"messageHintRule":"If any message-shape hint remains, keep it as non-final bullets and say real examples come after leads are found and filtered.","approvalBoundaryRule":"Keep this gate positive and short: ask approve/revise, then move to choosing where to find buyers.","sectionLabelRule":"Use ## Sender and Company for the person/company context; never render ## Campaign Identity.","skipIf":"the full brief was already rendered in the current shell-creation handoff before create_campaign returned","renderOnceRule":"Brief visible once before approval. If shown before shell creation, do not repeat after; append one watch-link handoff, then ask.","copyMustAvoid":["duplicate brief render after shell creation","second Watch link:"]},{"action":"ask_brief_choice","uses":"request_user_input","choices":["Approve brief + activate YOLO mode (Recommended)","Approve brief + build campaign with AI, step by step","Revise brief"],"skipIf":"yolo_mode; auto_continue after rendering assumptions unless brief quality floor fails","question":"Does this brief look right, and how should Sellable continue?","autonomousChoice":"Approve brief + activate YOLO mode (Recommended)","choiceDescriptions":{"Approve brief + activate YOLO mode (Recommended)":"Sellable will auto-decide the remaining setup choices with best guesses, including sources, filters, and messaging. It still stops before final launch.","Approve brief + build campaign with AI, step by step":"Approve this direction, then work with the AI through each major setup decision before it continues.","Revise brief":"Change the target, offer, proof, or campaign direction before continuing."}}],"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","sourceSelectionFunnel":{"preScoutRecommendationGate":{"required":true,"mustHappenBefore":["get_provider_prompt","search_signals","search_sales_nav","search_prospeo_companies","confirm_prospeo_company_accounts","search_prospeo","fetch_post_engagers"],"show":["buyer groups or places we could check","best place to start","where the right buyers are already talking","what signs the next search will check","where to look next if the first place is too thin","what approval authorizes"],"approvalAuthorizes":"best places to find buyers; no one added yet","explanationMustInclude":["why that place fits this campaign","enough likely prospects","what counts as a good sign","I won't add anyone yet"],"yoloMode":{"autoApproveRecommendedLane":true,"mustShowAssumedChoice":true,"pauseIfConfidenceLow":true},"customerLanguage":{"readability":"grade-5","requiredHeading":"Find Buyers Plan","prefer":["people to check","prospects"],"avoid":["lane","precision/scale tradeoff","evidence quality","workflow pain","ICP"],"termRule":{"buyers":"target market","peopleToCheck":"raw reactions/comments before fit is known","prospects":"likely usable people after fit","leads":"campaign rows"}},"questionOrder":"update_campaign to pick-provider; render Find Buyers Plan without repeating the watch link; never ask first; exactly one structured source-plan question total.","approvalFreshnessRule":"Do not reuse brief approval; continue exact earlier source-plan choice instead of asking a second identical question.","copyMustAvoid":["Watch link:","watch-link handoff"]},"defaultWhenSourceUnspecified":["signal-discovery","sales-nav-recent-active","sales-nav-general","prospeo"],"parallelAllowedOnlyWhen":["user explicitly requested source comparison"]},"onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"pick-provider","watchNarration.stage":"find-leads","watchNarration.headline":"Review where to find buyers","watchNarration.visibleState":"Source selection is visible before lead finding.","watchNarration.agentIntent":"Codex is explaining where to look first and fallback.","watchNarration.nextAction":"Approve where to look first or choose another place","watchNarration.safety":"Only deciding where to look. No one is added yet."}},{"action":"render_find_buyers_plan_inline","oneShot":true,"requiredPrecondition":"currentStep=pick-provider has been saved with update_campaign","mustHappenAfter":["update_campaign currentStep=pick-provider"],"mustHappenBefore":["ask_find_buyers_plan_choice","get_provider_prompt","search_signals","search_sales_nav","search_prospeo_companies","confirm_prospeo_company_accounts","search_prospeo","fetch_post_engagers"],"output":"normal chat text before any request_user_input approval panel","requiredHeading":"Find Buyers Plan","requiredInlineFields":["buyer groups or places for this campaign","best place to start","why that place fits this campaign","where to look next if thin","what approval authorizes"],"copyMustInclude":["choose where to find buyers","I won't add anyone yet"],"copyMustAvoid":["lane","source scouting","provider","precision/scale tradeoff","evidence quality","pilot volume","ICP","workflow pain","lead-source scouting","not importing leads","Watch link:","campaign-builder URL","repeat the watch URL","watch-link handoff"],"approvalBoundary":"Approves where to look; no one added yet.","linkPolicy":"Do not include another watch link."},{"action":"ask_find_buyers_plan_choice","uses":"request_user_input","oneShot":true,"requiredPrecondition":"visible plan rendered; no earlier approval can satisfy this unless exact visible source choice exists; do not ask this if that exact earlier source choice exists","skipIf":"earlier source-plan question already captured exact visible source choice, post-plan provider, or yolo choice","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","copyMustInclude":["Approve this plan for where to find buyers?","Start with LinkedIn posts"],"mustNotHappenBefore":["render_find_buyers_plan_inline"],"approvalStateRule":"Never ask a second identical source-plan question; set source_lane_approved only after visible plan, never from brief approval/generic/pre-plan state."},{"action":"persist_provider_search_step_before_search","tool":"update_campaign","requiredPrecondition":"source_lane_approved set after the visible Find Buyers Plan approval question","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_companies","confirm_prospeo_company_accounts","search_prospeo","fetch_post_engagers"]},{"action":"run_parent_thread_source_funnel","requiredPrecondition":"source_lane_approved after visible Find Buyers Plan approval","mode":"parent_thread_inline_sequential","sourceAgents":"forbidden in normal create-campaign","loadsOnlyActiveProviderPrompt":true,"defaultOrder":["signal-discovery","sales-nav-recent-active","sales-nav-general","prospeo"],"stopOnFirstViableUnlessComparisonRequested":true}],"requiredCampaignState":["campaignId","campaignBrief","currentStep"],"allowedTools":["get_provider_prompt","lookup_sales_nav_filter","search_sales_nav","search_prospeo_companies","confirm_prospeo_company_accounts","search_prospeo","search_signals","select_promising_posts","fetch_post_engagers","fetch_company","fetch_linkedin_profile","load_csv_dnc_entries","load_csv_linkedin_leads","load_csv_domains","get_rows_minimal","update_campaign","AskUserQuestion","request_user_input","get_campaign_navigation_state"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign","Task","spawn_agent"],"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":"Start Import approval","onEnter":[{"action":"show_source_decision_card","requiredInlineFields":["primary source and exact filters/recipe","Start Import 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 happens after Start Import"],"copyMustAvoid":["lead-source scouting","source scouting","headline-fit","engagers needed","execution slice","ICP","good buyers","real buyers","This approval covers","It does not approve","does not approve filters","filters, messages, sender selection","sender selection, sequence, or sending","Watch link:","campaign-builder URL","repeat the watch URL"],"approvalBoundaryRule":"Use positive Start Import copy only: after approval build source list, add to campaign, review first 15 leads; never list future non-approvals.","linkPolicy":"Do not include another watch link in Source Recommendation; describe the Start Import decision only."},{"action":"ask_source_review_choice","uses":"request_user_input","choices":["Approve scraping N recommended LinkedIn posts","Start Import for the approved source list","Revise source","Pause here"],"approvalChoiceLabelsByProvider":{"signal-discovery":"Approve scraping {scrapePostCount} recommended LinkedIn posts?","sales-nav":"Start Import for the approved Sales Nav source list","prospeo":"Start Import for the approved Prospeo source list"},"postApprovalContract":{"singleUseApproval":true,"doNotRepeatAfterApproval":["Source Recommendation","show_source_decision_card","ask_source_review_choice"],"requiredNextActionAfterApproval":"get_provider_prompt then import_leads","signalDiscoveryNextTool":"get_provider_prompt then import_leads"},"autoSelectIf":"yolo_mode and projected usable pool clears the source quality floor","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]}],"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","currentStepValue":"auto-execute-leads","reference":"references/step-13-import-leads.md","onEnter":[{"tool":"get_subskill_prompt","requiredValues":{"subskillName":"create-campaign-v2-tail"}},{"tool":"get_provider_prompt"},{"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","repeatUntil":"ready_true_or_cancelled_or_import_failed","requiredValues":{"requireComplete":true},"onImportStillRunning":"re-run wait_for_lead_list_ready; do not call confirm_lead_list just because rows exist","partialOverrideRule":"Only if the user explicitly asks to keep going early may the next confirm_lead_list call pass allowPartialSourceList: true."},{"tool":"confirm_lead_list","requiredFields":["campaignOfferId","selectedLeadListId","reviewBatchLimit"],"requiredValues":{"reviewBatchLimit":15},"capture":["workflowTableId","reviewBatchRowIds"],"requiredPrecondition":"wait_for_lead_list_ready returned ready:true, unless the user explicitly asked to keep going early with a partial list","partialOverrideField":"allowPartialSourceList:true only after explicit user early-continue instruction","mustNotRunWhen":["wait_for_lead_list_ready reason=import_still_running and no explicit early-continue instruction","wait_for_lead_list_ready reason=cancelled","wait_for_lead_list_ready reason=import_failed","missing import job metadata"]},{"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","maxCustomerCopyLines":4,"copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"linkPolicy":"Ask add filters vs skip filters without repeating the watch link.","purpose":"ask filter choice immediately"}],"requiredCampaignState":["campaignId","providerSearchAssociation","selectedLeadListId"],"allowedTools":["get_provider_prompt","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"},"hardRules":["import_leads_then_repeated_wait_for_lead_list_ready_then_confirm_lead_list_then_wait_for_campaign_table_ready","partial_source_rows_do_not_unblock_confirm_lead_list_without_explicit_user_early_continue","cancelled_or_failed_source_import_stops_before_campaign_table_copy"]},{"id":"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","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"copyMustInclude":["source rows are in the campaign","use filters while Message Drafting runs or skip filters"]}],"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_prospect_setup_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":"prospect-setup","filters_skipped":"prospect-setup","revise_leads":"find-leads"}},{"id":"prospect-setup","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":"Filter Rules is visible while Codex drafts/saves filters.","watchNarration.nextAction":"Review saved filter rules"},"mustRunBefore":["get_post_find_leads_scout_registry","launch_message_drafting_after_filter_choice","load_filter_reference_in_parent","save_rubrics","ask_filter_rubric_review_choice"]},{"tool":"get_post_find_leads_scout_registry","returns":["post-find-leads-message-scout"],"rule":"normal post-import registry exposes only Message Drafting; filters are parent-thread MCP work","mustRunBefore":["launch_message_drafting_after_filter_choice","get_subskill_asset:references/filter-leads.md","save_rubrics","ask_filter_rubric_review_choice"],"registryOnlyIsNotLaunch":true},{"action":"launch_message_drafting_after_filter_choice","mode":"background_agent_when_host_supports_subagents","target":"post-find-leads-message-scout","when":"filters_enabled or filters_skipped after filter-choice answer","doesNotQueueCells":true,"customerNarration":"Message Drafting is preparing.","inputs":["campaignId","workflowTableId","brief/source summary","3-5 sample workflow-table rows","optional campaignName/selectedLeadListId/filterChoice"],"forbiddenSiblings":["source/filter workers"],"handoffCompression":"lean_message_drafting_handoff_no_hashes_no_counts_no_full_row_data","requiredConcreteToolCall":"Task or spawn_agent when host supports background agents","registryOnlyIsNotLaunch":true,"mustRunBefore":["get_subskill_asset:references/filter-leads.md","load_filter_reference_in_parent","save_rubrics","ask_filter_rubric_review_choice"],"yoloPermissionRule":"do not ask the user for worker permission in YOLO.","startProof":"Message Drafting counts as started only after Task/spawn_agent.","noBackgroundFallback":"Start the same full message branch inline before filter reference or block."},{"action":"continue_after_drafting","when":"filters_skipped","transition":"filters_skipped_message_started"},{"tool":"get_subskill_asset","action":"load_filter_reference_in_parent","when":"filters_enabled","requiredValues":{"subskillName":"create-campaign-v2","assetPath":"references/filter-leads.md"},"rule":"Parent thread uses this reference to draft production rubrics; do not spawn a filter worker."},{"tool":"save_rubrics","when":"filters_enabled","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":["Filter rules saved for review","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 saved filter rules","Approve these filter rules."],"autoSelectIf":"yolo_mode and parent saved production-shaped rubrics","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"requiredPrecondition":"save_rubrics succeeded or active campaign rubrics verified"}],"requiredCampaignState":["campaignId","campaignBrief","selectedLeadListId","workflowTableId"],"allowedTools":["get_post_find_leads_scout_registry","get_subskill_asset","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","filters_skipped_message_started"],"hardRules":["after_save_rubrics_currentStep_must_stay_create-icp-rubric_until_filter_approval","filter_approval_required_before_apply-icp-rubric_or_queue_campaign_cells","do_not_move_browser_to_messages_until_filter_leads_step_is_current_or_filters_are_explicitly_skipped","no_prospect_setup_worker_or_deep_prompt_before_filter_choice","message_drafting_after_filter_choice","message_drafting_no_cells","only_message_drafting_may_spawn_background_agent","filters_are_parent_thread_mcp_work","no_post_find_leads_filter_scout_in_normal_path","registry_call_is_not_message_drafting_launch","yolo_must_not_ask_permission_for_message_drafting_worker","message_drafting_must_start_before_filter_reference_or_save_rubrics","if_background_agent_unavailable_start_full_message_branch_inline_before_filters_or_block","message_drafting_start_does_not_advance_filter_path"],"transitions":{"filter_rubrics_approved":"message-generation","revise_leads":"find-leads","revise_rubric":"filter-rubric","revise_messaging":"message-generation","confirm_with_user":"message-review","filters_skipped_message_started":"message-generation"}},{"id":"filter-rubric","onEnter":[{"tool":"get_subskill_asset","requiredValues":{"subskillName":"create-campaign-v2","assetPath":"references/filter-leads.md"}},{"action":"observed-row-grounding","uses":["get_rows_minimal","get_rows","enrich_with_prospeo"],"requiredBefore":"save_rubrics","contract":["Call get_rows_minimal before drafting filters.","Call get_rows({ tableId, rowIds }) for row/enrichment sample; rowIds must be a JSON array, not a comma-delimited string.","Use multiple visible rows for repeated false positives, broad enterprise sellers, noisy titles, agencies/vendors, geography, and budget gaps.","Use one direct enrichment sample via enrich_with_prospeo if rows are thin; set enrichMobile: false.","On direct enrichment failure, no credits, provider error, or no match, do not retry; continue with uncertainty or block.","If no rows, do not enrich or save row-grounded filters; ask/import rows or use brief/source with uncertainty.","If zero enriched fields, separate raw row fields from unavailable enrichment; do not pretend enrichment-backed filters are observed.","Stop before save_rubrics on stale workflowTableId/source/campaignId/row ids.","Fail generic sales/BD/partnerships unless target/current evidence proves fit and budget path.","No standalone current_role_* safety; fold into keep/exclude or engagement_only_or_stale_fit_exclusion."]},{"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","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]}],"requiredCampaignState":["campaignId","workflowTableId"],"allowedTools":["get_subskill_asset","get_rows_minimal","get_rows","enrich_with_prospeo","save_rubrics","AskUserQuestion","request_user_input"],"doNotAllow":["create_campaign","list_senders","import_leads","confirm_lead_list","update_campaign","queue_cells","start_campaign","check_rubric","queue_campaign_cells","bulk_enrich_with_prospeo"],"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","onEnter":[{"action":"set_message_review_visible_step_by_filter_choice","tool":"update_campaign","watchNarration.stage":"fit-message","requiredValues":{"currentStep":"apply-icp-rubric","watchNarration.stage":"fit-message","watchNarration.headline":"Filters saved + waiting for message approval"},"watchNarrationRule":"After filter approval, show Filter Leads; do not queue enrichment/filter/message cells before approve-message.","mustRunBefore":"run_or_reconcile_message_draft_builder","failureRule":"currentStep=apply-icp-rubric"},{"action":"run_or_reconcile_message_draft_builder","target":"post-find-leads-message-scout","toolCallRequiredBeforeDraft":["Task/spawn_agent or inline fallback before parent drafting","generic gpt-5.5 xhigh Message Drafting fallback","lean handoff: campaignId, workflowTableId, brief, source rule, 3-5 rows","no copied counts, hashes, full row ids, broad row data, or artifacts","branch loads current brief/context, full generate-messages prompt/assets","return labeled Markdown: template, token rules, sample, status, recommendation, validation, hash, retry","hide fallback sample, risk notes, and qaReceipt on happy path","inline fallback=parent-thread-fallback; same gates"],"stateSource":"live campaign/table plus sample rows","outputState":"messageDraftRecommendation with internal validation passed","revisionMode":{"when":"revise_messaging, message QA request, or latest user message requests template changes before approve-message","route":"send feedback/QA/rewrite request to post-find-leads-message-scout or generic gpt-5.5 xhigh Message Drafting branch","requiredInputs":["latest user feedback","current messageDraftRecommendation and basisToken/outputHash","lean campaign/table basis and brief summary; branch reloads live state"],"forbiddenParentActions":["rewrite template in parent","QA template in parent from memory","update_campaign_brief before approve-message"],"output":"revised messageDraftRecommendation rendered before request_user_input"},"onlyMessageBackgroundAgent":true,"forbiddenSiblingAgents":["source-scout-*","any filter background worker"],"handoffCompression":"lean_message_handoff","finalGateRequiredBeforeReady":"Load create-campaign-v2-validation before ready."}],"requiredCampaignState":["campaignId","campaignBrief","selectedLeadListId","workflowTableId"],"allowedTools":["get_subskill_prompt","get_campaign","get_rows_minimal","update_campaign","Task","spawn_agent"],"toolRules":["message_drafting_agent_first_no_silent_parent_fallback; yolo counts","on_filters_enabled_path_parent_must_not_enter_message_review_until_save_rubrics_success_and_filter_approval","brief.md, lead-review.md, and lead-sample.json are optional debug context only.","messageDraftRecommendation returns template, token rules, rendered sample, status, recommendation, validation, hash, retry.","messageDraftRecommendation hides fallback/risk/qaReceipt in the happy path.","If campaign/table/sample basis does not match, classify the output stale or blocked.","message_revision_feedback_routes_to_message_drafting_agent_not_parent","message_qa_routes_to_message_drafting_agent_not_parent","message_drafting_loads_full_generate_messages_prompt_all_chunks","message_drafting_loads_all_reference_assets_via_get_subskill_asset","message_drafting_loads_create_campaign_v2_validation_prompt_before_return","message_drafting_handoff_uses_lean_basis_no_hashes_counts_or_full_rows","message_drafting_loads_current_campaign_brief_before_drafting","parent_may_load_generate_messages_only_for_explicitly_approved_inline_fallback","before return branch loads create-campaign-v2-validation prompt and runs internal validation","pre_approval_step_filter_leads"],"doNotAllow":["create_campaign","list_senders","save_rubrics","import_leads","confirm_lead_list","queue_cells","start_campaign","generate_messages","AskUserQuestion","request_user_input"],"waitFor":["message_validation_ready","revise_rubric","revise_messaging"],"transitions":{"message_validation_ready":"message-review","revise_rubric":"filter-rubric","revise_messaging":"message-generation"},"revisionLoop":{"trigger":"user gives copy feedback, asks for QA/update, or chooses revise-messaging","required":["route latest user feedback or QA request to Message Drafting with current recommendation and live campaign/table state","produce a new messageDraftRecommendation with revisionNotes or validationStatus","render revised ## Message Template, ## Rendered Example, and What changed before asking approval"],"blocked":["asking whether an unseen new version is better","reusing the old template after acknowledging feedback","rewriting the template in the parent thread","update_campaign_brief before approve-message","request_user_input or AskUserQuestion during message-generation","QAing the template in the parent thread"],"outputState":"messageDraftRecommendation"},"hardRules":["message_revision_must_render_new_template_before_approval_question","message_revision_saves_only_after_approve_message","message_generation_must_not_call_request_user_input","message_generation_must_transition_to_message_review_only_after_renderable_draft_state","message_drafting_agent_first_no_silent_parent_fallback","message_revision_routes_to_message_drafting_agent","message_qa_routes_to_message_drafting_agent","filter_path_requires_saved_filters_before_message_review","only_message_drafting_may_spawn_background_agent","no_queue_before_template_approval"],"currentStepValue":"apply-icp-rubric"},{"id":"message-review","onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"apply-icp-rubric","watchNarration.stage":"fit-message"},"watchNarrationRule":"Before template approval, keep browser on Filter Leads.","mustRunBefore":"render_message_review_from_state","failureRule":"do not ask for message approval until Filter Leads shows and cells unqueued."},{"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":["Rendered fallback sample","Concerns","QA receipt","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","validation notes","QA details"],"copyMustInclude":["one recommended template","one rendered sample","token rules and fallbacks","full list remains paused"],"copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"revisionRenderRule":"After feedback, route feedback to Message Drafting; show revised template/example; never ask if an unseen version is better.","parentMustNot":["rewrite template from memory","invent validation summary without Message Drafting output","render qaReceipt, risk notes, or renderedFallbackSample on the normal happy path"]},{"action":"ask_message_review_choice","uses":"request_user_input","choices":["approve-message","revise-messaging"],"copyMustInclude":["approve this message template and continue","template approval only locks the draft direction; final Start still controls sending"],"autoSelectIf":"yolo_mode and Recommendation is approve-message; revise autonomously when Recommendation is revise-messaging","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"requiredPrecondition":"current or revised template and rendered example are visible in this turn","revisionPrecondition":"after revise_messaging, revised template is visible before this question"},{"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","revisionApprovalRule":"If the user requested revisions, write only the latest Message Drafting-approved revised template and token rules after approve-message.","forbiddenBefore":"approve-message"}],"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"},"currentStepValue":"apply-icp-rubric"},{"id":"validate-sample","currentStepValue":"apply-icp-rubric","reference":"references/sample-validation-loop.md","visibleStepRule":"After approvals, queue bounded enrichment.","onEnter":[{"tool":"update_campaign","requiredValues":{"currentStep":"apply-icp-rubric","watchNarration.stage":"fit-message"},"watchNarrationRule":"Template saved; Filter Leads runs bounded enrichment/scoring."},{"tool":"queue_campaign_cells","requiredFields":["workflowTableId","columnRole","rowSelector"],"requiredValues":{"columnRole":"enrich","rowSelector":{"type":"reviewBatch"},"forceRerun":false},"targetCountSource":"reviewBatch.rowCount default 15"},{"tool":"wait_for_campaign_processing","requiredFields":["workflowTableId","minPassedCount"],"requiredValues":{"minPassedCount":1},"readVia":"stats_only_tool_result","timeoutGuidance":"On timeout, use partial diagnostics; do not repeat identical waits.","customerSummaryPattern":["{checked} leads checked","{passed} passed fit scoring","{blocked} blocked before sending","full list remains paused until approval"]},{"action":"handle_partial_or_timeout_sample","customerStatus":"sample-needs-revision","rule":"Surface partial status and route to revision.","copyMustInclude":"completed, passed, pending, blocked, paused"}],"requiredCampaignState":["campaignId","workflowTableId","approvedMessageTemplate","filterRubricsApproved when enableICPFilters=true"],"allowedTools":["get_subskill_asset","queue_campaign_cells","select_campaign_cells","get_campaign_table_schema","get_rows_minimal","record_campaign_review_batch","wait_for_campaign_processing","update_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["import_leads","list_senders","start_campaign","enrich_with_prospeo","bulk_enrich_with_prospeo","check_rubric"],"hardRules":["campaign_processing_waits_are_stats_only_by_default","queue_review_batch_by_selector_never_fetch_rows_for_cell_ids","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":"filter-rubric","revise_leads":"find-leads","revise_rubric":"filter-rubric","escalation_triggered":"escalation","new_sample":"validate-sample"}},{"id":"auto-execute-messaging","currentStepValue":"auto-execute-messaging","references":["references/parallel-critique-protocol.md","references/thomas-variant-selection.md","references/sellable-cleanup-rules.md","references/step-15-re-cascade.md"],"onEnter":[{"tool":"queue_campaign_cells","batchSize":100,"when":"any passing row has pending, empty, or stale Generate Message cell","requiredFields":["workflowTableId","columnRole","rowSelector"],"requiredValues":{"columnRole":"generateMessage","rowSelector":{"type":"needsGeneratedMessage"},"forceRerun":false},"cellSource":"selector-engine needsGeneratedMessage rows using approved campaign brief template"},{"tool":"wait_for_campaign_processing","purpose":"wait_for_first_current_revision_generated_message","requiredValues":{"minGeneratedMessages":1,"templateRevision":"current"},"readVia":"stats_only_tool_result","invariant":"A generated message implies the pass gate; stale or wrong-revision messages are excluded from readiness."},{"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","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","this approves reviewed draft rows for setup; final Start still controls sending"],"autoSelectIf":"yolo_mode and the first passing generated message clears the quality floor","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]}],"allowedTools":["get_subskill_asset","get_campaign_table_schema","select_campaign_cells","queue_campaign_cells","wait_for_campaign_processing","revise_message_template_and_rerun","update_campaign","AskUserQuestion","request_user_input","update_cell"],"doNotAllow":["import_leads","list_senders","start_campaign","generate_messages"],"hardRules":["generated_message_count_excludes_stale_or_wrong_revision_messages","message_template_revision_uses_brief_update_then_generate_message_rerun","do_not_overwrite_generated_message_cells_directly","critique_failure_never_escalates","critique_sample_size_bounded_by_config","first_passing_generated_message_unblocks_review","critics_fixed_at_targeting_copy_voice","synthesis_enforces_message_token_contract","opus_reserved_for_highest_value_subset","proposed_token_never_persisted_in_rewrite","approve_reviewed_rows_via_semantic_approved_selector_not_get_rows_approveCellId"],"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","currentStepValue":"awaiting-user-greenlight","reference":"references/final-handoff-contract.md","onEnter":[{"tool":"start_campaign_message_preparation","requiredValues":{"targetPreparedMessages":"{requestedMessageCount}","approvalMode":"{scheduleOrApproveIntent ? 'approve' : 'mark_ready'}"},"intentMapping":{"scheduleSends":"approve the exact requested send count"},"when":"explicit_count_or_schedule","batchStrategy":"max100_serial","rowBudgetStrategy":"sample100_cap300"},{"tool":"get_campaign_message_preparation_status","copyMustInclude":["preparation job status","checked rows","target","stop reason"],"when":"prep_job_started"},{"tool":"get_campaign"},{"tool":"list_senders","purpose":"identity proof at Settings"},{"tool":"update_campaign","requiredValues":{"currentStep":"settings","watchNarration.stage":"review-ready"},"watchNarrationRule":"Say message review is complete, Settings is open, lead research/filtering happened outside LinkedIn, and nothing sends until Start."},{"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"],"copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]},{"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 one exact identity match","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"],"noAutoSelectIf":"identity proof is missing; ask"},{"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 app is moving to Sequence review; sequence remains editable and nothing sends until Start."},{"tool":"attach_recommended_sequence","when":"after senderIds are attached","requiredValues":{"campaignId":"{campaignId}","currentStep":"send","watchNarration.stage":"review-ready"},"watchNarrationRule":"Say the recommended follow-up sequence is attached, final launch review is open, and nothing sends until Start."},{"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,"copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]}],"allowedTools":["cancel_campaign_message_preparation","get_campaign_message_preparation_status","start_campaign_message_preparation","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","reference":"references/final-handoff-contract.md","onEnter":[{"tool":"get_campaign"},{"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"],"boundedLaunchRule":"preparation job approved X; no broad approve-all."},{"tool":"start_campaign","requiredFields":["campaignId"],"persistsCurrentStep":"running","watchNarrationRule":"After start_campaign succeeds, say final greenlight was accepted, campaign is live/running, and progress can be watched."}],"allowedTools":["get_campaign","attach_recommended_sequence","start_campaign","AskUserQuestion","request_user_input"],"watchRequired":true,"waitFor":"campaign_started","transitions":{"campaign_started":"running"}},{"id":"running","currentStepValue":"running","onEnter":[{"action":"surface_campaign_live_confirmation_without_watch_link","copyMustAvoid":["Watch link:","campaign-builder URL","repeat the watch URL"]}],"allowedTools":["get_campaign","AskUserQuestion","request_user_input"],"doNotAllow":["start_campaign"],"terminal":true},{"id":"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","allowedTools":["AskUserQuestion","request_user_input"],"terminal":true}]}
@@ -505,6 +505,30 @@ authority, account fit, capacity, geography, and exclusions.
505
505
  - Do not make the filter so narrow that it contradicts the approved source
506
506
  unless campaign-row evidence clearly requires it.
507
507
 
508
+ ## Zero-Pass Recovery Contract
509
+
510
+ If the later bounded review batch scores `0/N` after saved filters are approved,
511
+ the parent thread must check rule relaxability and same-source sample viability
512
+ before changing lead source.
513
+
514
+ Use the saved rule reasoning and observed miss patterns to answer:
515
+
516
+ - would one or two rubric edits let at least one real ICP buyer pass?
517
+ - is the same source still viable, but the current review batch unrepresentative
518
+ enough to justify a fresh same-source sample?
519
+ - would role/function, account fit, economic capacity, geography, and
520
+ competitor/vendor/wrong-side safety still be protected?
521
+ - did the miss happen because a rule demanded unavailable or over-specific
522
+ evidence, or because the rows are genuinely wrong?
523
+
524
+ If a safe relaxation exists, revise/save rubrics and rerun the same review
525
+ batch before re-sourcing. If the rules are right but the first slice is probably
526
+ unrepresentative, record and run a fresh review batch from the same approved
527
+ source before re-sourcing. If the only way to get a pass is to accept bad-fit
528
+ rows, source engagement as qualification, vendors/competitors, wrong-side
529
+ marketplace actors, wrong function, or no budget path, classify it as
530
+ `revise-find-leads` and change the source.
531
+
508
532
  ## Prohibited During Normal Create-Campaign
509
533
 
510
534
  - calling `check_rubric`
@@ -41,9 +41,12 @@ Before asking for sample/message approval, include this compact receipt:
41
41
  Also include the reputation guardrail: weak personalization can burn the sender's reputation, so this approval is only for the reviewed sample/message direction. The full list remains paused until approval, and final launch happens later. Use the plain heuristic: "Would I take this call?"
42
42
 
43
43
  If the answer is yes, proceed to Step 15 messaging for the initial campaign rows. If
44
- the answer is no, diagnose whether the brief is wrong or the list is wrong,
45
- and either revise brief autonomously OR escalate to the user — never
46
- auto-revise leads.
44
+ the answer is no, first run the rule-relaxability audit below. Then diagnose
45
+ whether the filters are too strict, the brief is wrong, or the list/source is
46
+ wrong. Revise filters before changing source when a safe filter edit would
47
+ produce real ICP passes. Escalate or re-source only when the passing version
48
+ would be too loose or the list/source is clearly contaminated. Never silently
49
+ rerun `import_leads`.
47
50
 
48
51
  ## Inputs
49
52
 
@@ -103,8 +106,9 @@ auto-revise leads.
103
106
  `Status: sample-needs-revision`
104
107
  - show the concrete numbers: completed, passed, pending, pass percent, and
105
108
  message count when available
106
- - offer the next product choices: revise source, revise filter/rubric, or
107
- wait once only if there is active processing
109
+ - offer the next product choices: revise filter/rubric, pull a fresh
110
+ same-source sample, revise source, or wait once only if there is active
111
+ processing
108
112
  - never advance to Settings or awaiting-user-greenlight on a timeout or
109
113
  underfloor partial sample
110
114
 
@@ -119,10 +123,16 @@ auto-revise leads.
119
123
  one passing generated message is ready, stop for user review instead of
120
124
  waiting for a stronger sample.
121
125
  else:
122
- diagnose (see Brief-vs-List Diagnosis below)
126
+ diagnose (see Zero-Pass Rule-Relaxability Audit and Brief-vs-List Diagnosis below)
123
127
  revisionRound += 1
124
128
  if revisionRound > maxRevisionRounds:
125
129
  ESCALATE (see references/escalation-ladder.md)
130
+ else if diagnosis == "filter-relaxable":
131
+ revise filter/rubric first
132
+ save updated rubrics, get approval if not in yolo mode, rerun same review batch
133
+ else if diagnosis == "sample-refresh":
134
+ record a fresh same-source review batch
135
+ queue enrichment for the new reviewBatch and rerun this loop
126
136
  else if diagnosis == "brief":
127
137
  autonomous update_campaign_brief with diagnostic
128
138
  rerun sample from step 1 of this loop
@@ -196,8 +206,9 @@ passed, move to Step 15 and observe or queue Generate Message for the passing
196
206
  rows; Step 15 stops when one generated message is ready. If zero rows have
197
207
  passed and no active processing is visible, stop at
198
208
  `Status: sample-needs-revision` before Settings. Show the completed / passed /
199
- pending counts and ask whether to revise source, revise filter/rubric, or wait
200
- once only if active processing is still visible and the wait args changed.
209
+ pending counts and ask whether to revise filter/rubric, pull a fresh same-source
210
+ sample, revise source, or wait once only if active processing is still visible
211
+ and the wait args changed.
201
212
 
202
213
  ## Projected Pass Math
203
214
 
@@ -221,9 +232,134 @@ When non-default importLimit/sampleSize are configured, the math scales
221
232
  the same way. In the default internal-slice mode, the slice size equals the
222
233
  import limit, so the projection is the actual pass count.
223
234
 
235
+ ## Zero-Pass Rule-Relaxability Audit
236
+
237
+ Before changing lead source after a 0-pass sample, audit whether the saved
238
+ rules are over-strict. This audit is required for `0/N` passes, including
239
+ partial samples such as `0/12` or `0/15`.
240
+
241
+ Use compact campaign/table state first:
242
+
243
+ - `wait_for_campaign_processing` stats for completed/passed/pending counts
244
+ - `get_campaign_table_schema` and `select_campaign_cells` for semantic cell
245
+ counts when useful
246
+ - `get_rows_minimal` only when row-level miss patterns are required; do not
247
+ retain raw row payloads or carryData
248
+
249
+ Write the diagnosis in chat/watch narration before taking recovery action:
250
+
251
+ - which rule(s) caused the zero-pass result
252
+ - whether one or two rubric edits would let at least one real ICP buyer pass
253
+ - whether the same source looks viable enough for a fresh review sample
254
+ - which hard gates would remain protected
255
+ - whether re-sourcing is required, and why
256
+
257
+ The recovery choices are exactly:
258
+
259
+ 1. Change rubric: safe rule relaxation or correction would let real ICP buyers
260
+ pass while preserving hard gates.
261
+ 2. New sample: the same approved source still looks viable, but the current
262
+ review batch is unrepresentative or poorly ordered.
263
+ 3. New lead source: the source/list is contaminated, exhausted, or would require
264
+ bad-fit relaxation to get passes.
265
+
266
+ Forbidden before the audit is written: do not call `search_signals`,
267
+ `search_prospeo`, `import_leads`, or `confirm_lead_list`. Those tools are only
268
+ allowed after the audit chooses "New lead source"; otherwise the next action is
269
+ rubric revision or a fresh same-source `reviewBatch`.
270
+
271
+ Matrix expectations:
272
+
273
+ | Scenario | Required recovery behavior |
274
+ | --- | --- |
275
+ | `0/15` strict-but-near-miss sample | Recommend safe rubric relaxation or a fresh same-source review batch before any new source work. |
276
+ | `0/15` source-noise sample | Reject unsafe relaxation, explain why it would pass bad-fit rows, then change source. |
277
+ | `0/15` with unprocessed same-source rows | Use `record_campaign_review_batch` and `rowSelector: { type: "reviewBatch" }` before any new source. |
278
+ | `0/15` with no viable same-source rows | Change source only after the relaxability audit says safe relaxation and same-source sampling are not viable. |
279
+ | `1/15` low-pass sample | Continue only if the pass/message floors are satisfied; otherwise run the same recovery decision tree. |
280
+ | healthy pass sample | Continue to message review without source revision. |
281
+
282
+ ### Filter-relaxable
283
+
284
+ Use this when at least one sampled row still looks like someone the user would
285
+ want to hear from, and the fix is a safer rubric boundary, not lower quality.
286
+
287
+ Signals:
288
+
289
+ - a rule depends on evidence that normal enrichment does not reliably provide
290
+ yet, but the row has other credible campaign-native evidence
291
+ - one proxy is too narrow, such as requiring an exact title token, exact company
292
+ stage, or exact tool mention when adjacent approved buyer evidence is present
293
+ - the miss cluster is caused by a single over-specific gate while role,
294
+ account, budget path, geography, and vendor/wrong-side safety remain intact
295
+ - the rule can be rewritten from "must prove X exact signal" to "Yes if X or
296
+ equivalent campaign-native evidence proves the same buying role/problem"
297
+
298
+ Action: revise the rubrics first. Save the updated rubrics, get filter approval
299
+ again unless yolo mode can approve production-shaped criteria, then rerun the
300
+ same review batch. Do not go back to source selection first.
301
+
302
+ ### Fresh same-source sample
303
+
304
+ Use this when the saved rubrics are reasonable and the source thesis still
305
+ looks viable, but the current review batch is probably not representative.
306
+
307
+ Signals:
308
+
309
+ - the failed rows look like a broad first page, low-signal ordering, stale top
310
+ rows, or an unlucky slice rather than source contamination
311
+ - the source list/campaign table has enough unprocessed rows from the same
312
+ approved source to test another bounded set
313
+ - changing rules would not be the right fix, but the source itself is not bad
314
+ - at least some remaining rows have plausible buyer/account signals under the
315
+ approved source thesis
316
+
317
+ Action: choose explicit row IDs from the existing campaign table/source list,
318
+ call `record_campaign_review_batch({ tableId, rowIds })`, then queue:
319
+ `queue_campaign_cells({ columnRole: "enrich", rowSelector: { type: "reviewBatch" } })`.
320
+ Do not call `import_leads`, create a new source plan, or describe this as
321
+ finding new leads. This is a fresh sample from the same approved source.
322
+
323
+ ### Filter-too-relaxed
324
+
325
+ Use this when getting any pass would require removing a hard qualification gate
326
+ or converting source interest into ICP fit.
327
+
328
+ Signals:
329
+
330
+ - the only way to pass rows is to accept wrong-function, wrong-seniority,
331
+ wrong-side marketplace, vendor/competitor, wrong-geo, or no-budget-path rows
332
+ - the pass would rely on likes, comments, topical AI/GTM interest, recent
333
+ posting, source priority, or enrichment availability as the buyer-fit proof
334
+ - relaxing the rule would let through rows the user would not want to take a
335
+ call with
336
+
337
+ Action: do not loosen the rubrics. Classify as a list/source problem and route
338
+ to lead-source revision.
339
+
340
+ ### Source/list problem
341
+
342
+ Use this when the sample itself is wrong even under a reasonable rubric:
343
+
344
+ - most completed rows are outside the approved buyer/account thesis
345
+ - the source is contaminated by vendors, agencies, competitors, or the forbidden
346
+ marketplace side
347
+ - enrichment is blank or unusable for the fields the campaign needs
348
+ - no sampled row has a plausible buyer problem and budget/champion path
349
+
350
+ Action: stop the tail and route to lead-source revision. Explain that a filter
351
+ relaxation was checked first and would be too loose or would pass bad-fit rows.
352
+
353
+ Never say "I am finding new leads" immediately after `0/N` without this audit.
354
+ The expected order is: zero-pass count -> relaxability audit -> pick one of
355
+ change rubric, fresh same-source sample, or new lead source. Change source only
356
+ if the safe rubric version and same-source sampling cannot produce real ICP
357
+ passes.
358
+
224
359
  ## Brief-vs-List Diagnosis
225
360
 
226
- Before blindly revising, classify the failure. Three buckets:
361
+ After the rule-relaxability audit, classify any remaining failure. Three
362
+ buckets:
227
363
 
228
364
  ### Brief problem
229
365
 
@@ -312,9 +312,14 @@ else if wait_for_campaign_processing.ready === false and reason === "timeout":
312
312
  else:
313
313
  stop before Settings with Status: sample-needs-revision
314
314
  show completed, passed, pending, pass percent, and message count when available
315
- ask whether to revise source, revise filter/rubric, or wait once only if still processing
315
+ ask whether to revise filter/rubric, pull a fresh same-source sample,
316
+ revise source, or wait once only if still processing
316
317
  else:
317
- diagnose brief-vs-list per sample-validation-loop.md
318
+ run the zero-pass rule-relaxability audit, then diagnose per sample-validation-loop.md
319
+ - filter-relaxable: revise/save rubrics, approve when needed, then rerun
320
+ the same reviewBatch
321
+ - sample-refresh: record_campaign_review_batch with explicit same-source
322
+ rowIds, then queue reviewBatch enrichment and rerun this loop
318
323
  - brief: autonomous update_campaign_brief, then re-kick cascade with
319
324
  queue_campaign_cells({ columnRole: "enrich", rowSelector:
320
325
  { type: "reviewBatch" }, forceRerun: true }) and wait for the
@@ -336,14 +341,15 @@ A "list problem" diagnosis NEVER triggers autonomous
336
341
  A timeout or underfloor partial sample NEVER advances to Settings,
337
342
  awaiting-user-greenlight, or start-campaign. It must hand off as
338
343
  `sample_revision_required` with the observed counts so the user can decide
339
- whether the source or filter should change.
340
-
341
- If the same source lane has already failed after a revision, do not present
342
- another same-source revision as the recommended/default next action. Recommend
343
- the strongest fallback lane first (for example, Sales Nav after repeated
344
- Signals underfloor results), then offer revise-filter only if the imported rows
345
- look close to ICP but the rubric is too strict. This prevents customer-visible
346
- loops where the agent keeps asking to retry the same weak source.
344
+ whether to change the rubric, pull a fresh same-source sample, or change source.
345
+
346
+ If the same source lane has already failed after a safe rubric revision or a
347
+ fresh same-source sample, do not present another same-source retry as the
348
+ recommended/default next action. Recommend the strongest fallback source first
349
+ (for example, Sales Nav after repeated Signals underfloor results), then offer
350
+ revise-filter only if the imported rows look close to ICP but the rubric is too
351
+ strict. This prevents customer-visible loops where the agent keeps asking to
352
+ retry the same weak source.
347
353
 
348
354
  When the internal slice passes the projected-pass floor, call
349
355
  `update_campaign({ campaignId, currentStep: "auto-execute-messaging" })`