@sellable/mcp 0.1.101 → 0.1.103

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.
@@ -319,7 +319,8 @@ export function listSubskillPrompts(limit, includePublic, includeInternal) {
319
319
  };
320
320
  }
321
321
  function markSubskillPromptLoaded(subskillName) {
322
- if (subskillName === "create-campaign" || subskillName === "create-campaign-v2") {
322
+ if (subskillName === "create-campaign" ||
323
+ subskillName === "create-campaign-v2") {
323
324
  markCreateCampaignPromptLoaded();
324
325
  }
325
326
  if (subskillName === "research") {
@@ -30,6 +30,7 @@ export type AttachSequenceResponse = {
30
30
  export type AttachRecommendedSequenceInput = {
31
31
  campaignId: string;
32
32
  confirmed?: boolean;
33
+ currentStep?: string;
33
34
  };
34
35
  export type AttachRecommendedSequenceResponse = {
35
36
  success: boolean;
@@ -74,6 +75,7 @@ export declare const sequencerToolDefinitions: ({
74
75
  template?: undefined;
75
76
  confirmed?: undefined;
76
77
  campaignId?: undefined;
78
+ currentStep?: undefined;
77
79
  };
78
80
  required: string[];
79
81
  };
@@ -101,6 +103,7 @@ export declare const sequencerToolDefinitions: ({
101
103
  senderLinkedinUrl?: undefined;
102
104
  sequenceActions?: undefined;
103
105
  campaignId?: undefined;
106
+ currentStep?: undefined;
104
107
  };
105
108
  required: string[];
106
109
  };
@@ -118,6 +121,10 @@ export declare const sequencerToolDefinitions: ({
118
121
  type: string;
119
122
  description: string;
120
123
  };
124
+ currentStep: {
125
+ type: string;
126
+ description: string;
127
+ };
121
128
  name?: undefined;
122
129
  senderId?: undefined;
123
130
  clientProspectId?: undefined;
@@ -81,6 +81,10 @@ export const sequencerToolDefinitions = [
81
81
  type: "boolean",
82
82
  description: "Set true to overwrite existing sequence columns if the campaign already has a sequence attached",
83
83
  },
84
+ currentStep: {
85
+ type: "string",
86
+ description: "Optional CampaignOffer currentStep to persist with the sequence attach, usually 'send' after the recommended sequence is bound.",
87
+ },
84
88
  },
85
89
  required: ["campaignId"],
86
90
  },
@@ -178,6 +182,9 @@ export async function attachRecommendedSequence(input) {
178
182
  return await api.put(`/api/v3/campaigns/${input.campaignId}/sequence`, {
179
183
  autoSelectFromSenders: true,
180
184
  confirmed: input.confirmed,
185
+ ...(input.currentStep !== undefined
186
+ ? { currentStep: input.currentStep }
187
+ : {}),
181
188
  });
182
189
  }
183
190
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.101",
3
+ "version": "0.1.103",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -197,7 +197,7 @@ it was opened and observed.
197
197
  After every `update_campaign({ campaignId, currentStep })`, use
198
198
  `get_campaign_navigation_state` when available as a compact orientation check:
199
199
  match the browser-visible step to the saved campaign state, explain the current
200
- state in one sentence, and only then continue. Sender selection belongs at Settings after message approval and 10-row validation. Do not attach a sequence, start the campaign, or trigger a live send unless the user explicitly confirms that launch action outside UAT.
200
+ state in one sentence, and only then continue. Sender selection belongs at Settings after message approval and 10-row validation. After message validation, use Settings to help the user connect or select a LinkedIn sender. Explain Slack reply review before launch. After sender selection, attach the recommended sequence and move the watched UI to Send. Do not start the campaign or trigger a live send unless the user explicitly confirms that launch action outside UAT.
201
201
 
202
202
  ## Names To Use
203
203
 
@@ -568,7 +568,9 @@ updates.
568
568
  the brief, `pick-provider` or the selected provider step while sourcing,
569
569
  `filter-choice` after the 10-row review batch, `messages` or
570
570
  `auto-execute-messaging` for message work, `validate-sample` for validation,
571
- and `awaiting-user-greenlight` for Settings. Do not advance the step backward.
571
+ `awaiting-user-greenlight` for the final handoff, `settings` for sender
572
+ selection, `sequence` after sender attach, and `send` once the recommended
573
+ sequence is attached. Do not advance the step backward.
572
574
  7. Keep `selectedLeadListId` as the source list and `workflowTableId` as the
573
575
  campaign table. Do not use disk files as the post-mint source of truth.
574
576
  8. Do not ask the user to run another command.
@@ -107,9 +107,15 @@ Optional debug/UAT draft directory, disabled in normal customer runs:
107
107
  import, saved rubrics, and the approved message template. It must never queue
108
108
  workflow cells, attach a sequence, or start sending until rubrics are saved
109
109
  and the approved message set has been synced into the campaign brief.
110
- - Sender ownership stays out of this plan. senderIds persistence is Plan 04;
111
- update_campaign({ senderIds }) delegates to the v3 senders route and never
112
- uses the v2 campaign-offers PUT for sender persistence.
110
+ - Sender ownership belongs only to the final Settings handoff after message
111
+ validation. At that point the main thread may ask the user to connect or
112
+ select a LinkedIn sender, explain Slack reply review before launch, attach the
113
+ selected sender with `update_campaign({ senderIds, currentStep: "sequence" })`,
114
+ attach the recommended sequence, then move the watched UI to Send. It still
115
+ must not start sending until the user explicitly greenlights launch.
116
+ - senderIds persistence uses `update_campaign({ senderIds })`, which delegates
117
+ to the v3 senders route and never uses the v2 campaign-offers PUT for sender
118
+ persistence.
113
119
  - Load `core/flow.v2.json` through
114
120
  `get_subskill_asset({ subskillName: "create-campaign-v2", assetPath: "core/flow.v2.json" })`
115
121
  at the start of the run and treat the returned JSON as the active state
@@ -615,9 +621,11 @@ There are four customer-visible gates in the net-new hosted flow:
615
621
  one more messaging revision (`revise-messaging`). `approve-message` authorizes
616
622
  syncing the approved message set into the campaign brief, saving rubrics,
617
623
  importing the bounded 10-lead test batch, and queueing/observing that sample.
618
- - The sender/settings/sequence handoff is the launch gate. Starting the campaign
619
- still waits until a sender is attached, the sequence is accepted, and the user
620
- greenlights start.
624
+ - The sender/settings/sequence handoff is the launch gate. After message
625
+ validation, use Settings to help the user connect or select a LinkedIn sender.
626
+ Explain Slack reply review before launch. After sender selection, attach the
627
+ recommended sequence and move the watched UI to Send. Starting the campaign
628
+ still waits until the user explicitly greenlights start.
621
629
 
622
630
  Auto-continue without a structured question gate when the artifact says
623
631
  `Status: confirmed` (or equivalent), confidence is high/medium, volume is
@@ -58,6 +58,9 @@
58
58
  "message_set_synced_to_brief",
59
59
  "review_batch_imported",
60
60
  "settings_link_surfaced",
61
+ "sender_connection_required",
62
+ "sender_attached",
63
+ "ready_to_launch",
61
64
  "sequence_attached"
62
65
  ],
63
66
  "steps": [
@@ -2139,16 +2142,76 @@
2139
2142
  "purpose": "surface available connected senders if the campaign has none attached"
2140
2143
  },
2141
2144
  {
2142
- "action": "verify_sender_attached_or_route_to_settings",
2145
+ "tool": "update_campaign",
2146
+ "requiredValues": {
2147
+ "currentStep": "settings"
2148
+ },
2149
+ "purpose": "park the watched UI on Settings before sender selection"
2150
+ },
2151
+ {
2152
+ "tool": "get_campaign_navigation_state",
2153
+ "purpose": "confirm the watched UI is oriented to Settings before sender selection",
2154
+ "optional": true
2155
+ },
2156
+ {
2157
+ "action": "surface_sender_and_slack_handoff",
2143
2158
  "settingsUrlPattern": "/campaign-builder/{campaignId}/settings?mode=claude",
2144
- "onMissingSender": "surface settings link and STOP before sequence attach/start",
2145
- "onSenderAttached": "continue_to_sequence_selection"
2159
+ "requiredVisibleContent": [
2160
+ "connect or select a LinkedIn sender",
2161
+ "Slack reply review",
2162
+ "nothing starts until the user confirms launch"
2163
+ ],
2164
+ "onNoAvailableSender": "surface settings link and wait for sender_connection_required",
2165
+ "onAvailableSender": "ask the user which connected sender to attach"
2146
2166
  },
2147
2167
  {
2148
- "action": "verify_sequence_attached_or_route_to_sequence",
2149
- "sequenceUrlPattern": "/campaign-builder/{campaignId}/sequence?mode=claude",
2150
- "onMissingSequence": "surface sequence link and STOP before start",
2151
- "onSequenceAttached": "continue_to_greenlight_handoff"
2168
+ "action": "ask_sender_selection",
2169
+ "uses": "request_user_input",
2170
+ "singleChoice": true,
2171
+ "choices": [
2172
+ "Use this connected sender",
2173
+ "Connect a different sender in Settings",
2174
+ "Pause here"
2175
+ ],
2176
+ "uatSafety": "Only auto-select a mock/safe sender when an explicit UAT safe-mode sender is active; never select a real sender in UAT."
2177
+ },
2178
+ {
2179
+ "action": "attach_selected_sender",
2180
+ "tool": "update_campaign",
2181
+ "when": "user selected an available connected sender",
2182
+ "requiredValues": {
2183
+ "senderIds": [
2184
+ "{selectedSenderId}"
2185
+ ],
2186
+ "currentStep": "sequence"
2187
+ }
2188
+ },
2189
+ {
2190
+ "tool": "get_campaign_navigation_state",
2191
+ "purpose": "confirm the watched UI moved to Sequence after sender attach",
2192
+ "optional": true
2193
+ },
2194
+ {
2195
+ "tool": "attach_recommended_sequence",
2196
+ "when": "after senderIds are attached",
2197
+ "requiredValues": {
2198
+ "campaignId": "{campaignId}",
2199
+ "currentStep": "send"
2200
+ },
2201
+ "purpose": "bind the tier-aware recommended sequence before the launch decision"
2202
+ },
2203
+ {
2204
+ "tool": "update_campaign",
2205
+ "when": "sequence attach response does not persist currentStep",
2206
+ "requiredValues": {
2207
+ "currentStep": "send"
2208
+ },
2209
+ "purpose": "show the Send tab once sender and sequence are ready"
2210
+ },
2211
+ {
2212
+ "tool": "get_campaign_navigation_state",
2213
+ "purpose": "confirm the watched UI is on Send before final launch greenlight",
2214
+ "optional": true
2152
2215
  },
2153
2216
  {
2154
2217
  "action": "surface_watch_link",
@@ -2173,13 +2236,26 @@
2173
2236
  "fromConfig": "handoff.orientation"
2174
2237
  },
2175
2238
  {
2176
- "action": "stop_and_wait_for_greenlight"
2239
+ "action": "ask_final_launch_greenlight",
2240
+ "uses": "request_user_input",
2241
+ "singleChoice": true,
2242
+ "choices": [
2243
+ "Start campaign",
2244
+ "Review campaign first",
2245
+ "Pause here"
2246
+ ],
2247
+ "onUserStart": "claude-greenlight",
2248
+ "onReviewFirst": "awaiting-user-greenlight",
2249
+ "onPause": "awaiting-user-greenlight"
2177
2250
  }
2178
2251
  ],
2179
2252
  "allowedTools": [
2180
2253
  "get_subskill_asset",
2181
2254
  "get_campaign",
2255
+ "get_campaign_navigation_state",
2182
2256
  "list_senders",
2257
+ "update_campaign",
2258
+ "attach_recommended_sequence",
2183
2259
  "AskUserQuestion",
2184
2260
  "request_user_input"
2185
2261
  ],
@@ -2190,14 +2266,18 @@
2190
2266
  "autoStart": false,
2191
2267
  "watchRequired": true,
2192
2268
  "waitFor": [
2269
+ "sender_connection_required",
2193
2270
  "sender_attached",
2194
2271
  "sequence_attached",
2272
+ "ready_to_launch",
2195
2273
  "user_greenlight",
2196
2274
  "ui_start_detected"
2197
2275
  ],
2198
2276
  "transitions": {
2277
+ "sender_connection_required": "awaiting-user-greenlight",
2199
2278
  "sender_attached": "awaiting-user-greenlight",
2200
2279
  "sequence_attached": "awaiting-user-greenlight",
2280
+ "ready_to_launch": "awaiting-user-greenlight",
2201
2281
  "user_greenlight": "claude-greenlight",
2202
2282
  "ui_start_detected": "running"
2203
2283
  },
@@ -29,29 +29,42 @@ order (all before waiting for the user):
29
29
  least one attached sender and whether a sequence is already attached.
30
30
  2. Call `list_senders()` so the handoff can name available connected senders if
31
31
  the campaign has none selected.
32
- 3. If no sender is attached, surface the campaign Settings link
33
- `/campaign-builder/{campaignId}/settings?mode=claude`, tell the user to attach
34
- a sender there, and STOP. Do not attach sequence and do not start.
35
- 4. If a sender is attached but no sequence is attached, surface the campaign
36
- Sequence link `/campaign-builder/{campaignId}/sequence?mode=claude`, tell the
37
- user to accept or adjust the recommended sequence there, and STOP. Do not
38
- start. The Claude greenlight path may use
39
- `attach_recommended_sequence({ campaignId })` as an explicit repair after the
40
- user asks to start.
41
- 5. Re-surface the `watchUrl` using the exact block in
32
+ 3. Call `update_campaign({ campaignId, currentStep: "settings" })` and use
33
+ `get_campaign_navigation_state` when available so the watch link visibly
34
+ lands on Settings before sender setup.
35
+ 4. Explain sender setup and Slack in normal customer language: Sellable needs a
36
+ connected LinkedIn sender before anything can send, and Slack reply review
37
+ matters because replies and approvals need a channel the team will monitor.
38
+ 5. If no connected sender exists, surface the campaign Settings link
39
+ `/campaign-builder/{campaignId}/settings?mode=claude`, tell the user to
40
+ connect a sender there, and STOP. Do not attach sequence and do not start.
41
+ 6. If connected senders exist and no sender is attached, ask the user which
42
+ connected sender to attach. Attach only the chosen sender. In explicit UAT
43
+ safe mode, auto-select only the safe mock sender; never select a real sender.
44
+ 7. Call `update_campaign({ campaignId, senderIds: [selectedSenderId],
45
+ currentStep: "sequence" })` to attach the sender via the v3 senders route and
46
+ move the watch link to Sequence.
47
+ 8. Call `attach_recommended_sequence({ campaignId, currentStep: "send" })` to
48
+ bind the tier-aware recommended sequence. If that response does not persist
49
+ `currentStep: "send"`, call `update_campaign({ campaignId, currentStep:
50
+ "send" })`.
51
+ 9. Re-surface the `watchUrl` using the exact block in
42
52
  `references/watch-link-handoff.md`.
43
- 6. Surface the `handoff.orientation` string from `auto-execute.yaml`
44
- alongside the watch link so the user sees both the link and the
45
- "what to do next" sentence.
46
- 7. STOP. Do not call `start_campaign`. Do not advance `currentStep`.
53
+ 10. Surface the `handoff.orientation` string from `auto-execute.yaml`
54
+ alongside the watch link so the user sees both the link and the
55
+ "what to do next" sentence.
56
+ 11. Ask the final launch greenlight with the structured question function:
57
+ Start campaign, Review campaign first, or Pause here.
58
+ 12. STOP unless the user explicitly chooses Start campaign. Do not call
59
+ `start_campaign` from Step 16 itself.
47
60
 
48
61
  The final handoff must answer five customer questions in plain language:
49
62
 
50
63
  - where to inspect the campaign (`watchUrl`)
51
64
  - what is ready now (brief, filters/rubrics, review-batch leads, messages, and
52
- sequence when a sender is attached)
53
- - whether the next UI step is Settings because a sender still needs to be
54
- attached
65
+ sequence after a sender is attached)
66
+ - whether the next UI step is Settings, Sequence, or Send
67
+ - why the selected LinkedIn sender and Slack reply review matter before launch
55
68
  - what clicking Start does (approves/starts the campaign send path)
56
69
  - how to revise (reply with what to change, or use the campaign UI)
57
70
  - whether anything has started yet (nothing sends until the user starts)
@@ -67,8 +80,11 @@ When `lead-source-intake.json` exists, also answer:
67
80
  - for `existing-lead-list`, that the source list was reused, not recreated
68
81
 
69
82
  Use the exact state name `awaiting-user-greenlight` so logs and UX artifacts
70
- can verify the stop point, but explain it in normal words: the campaign is
71
- built and waiting for the user's final start decision.
83
+ can verify the state-machine stop point, but explain it in normal words: the
84
+ campaign is built, sender/sequence setup is being completed, and nothing sends
85
+ until the user's final start decision. The watched UI may advance through
86
+ Settings, Sequence, and Send while this state-machine step remains the final
87
+ handoff.
72
88
 
73
89
  The skill waits. It does not poll. A fresh continuation turn arrives
74
90
  either because the user said something in chat (Claude greenlight path)
@@ -79,9 +95,9 @@ the UI.
79
95
 
80
96
  ### UI path
81
97
 
82
- The user reviews messages in the watch link, attaches a sender in Settings when
83
- needed, chooses/accepts the sequence, bulk-approves messages in the workflow
84
- table UI (the existing "Approve all" button that wraps
98
+ The user reviews messages in the watch link, connects or selects a sender in
99
+ Settings when needed, reviews the recommended sequence, bulk-approves messages
100
+ in the workflow table UI (the existing "Approve all" button that wraps
85
101
  `POST /api/v3/workflow-tables/cells/approve-batch`), and clicks "Start Campaign"
86
102
  in the campaign-builder UI.
87
103
 
@@ -100,8 +116,8 @@ order, atomically:
100
116
  if already running.
101
117
  2. **Validate sender + sequence state.** If no sender is attached, refuse start
102
118
  and return the Settings link. If no sequence is attached but a sender is
103
- attached, call `attach_recommended_sequence({ campaignId })` before approving
104
- messages.
119
+ attached, call `attach_recommended_sequence({ campaignId, currentStep:
120
+ "send" })` before approving messages.
105
121
  3. **Bulk-approve queued messages** via the existing endpoint
106
122
  `POST /api/v3/workflow-tables/cells/approve-batch` with
107
123
  `{ tableId }`.
@@ -191,10 +207,11 @@ does NOT silently proceed.
191
207
  ## Hard Rules
192
208
 
193
209
  - The autonomous tail NEVER calls `start_campaign` on its own.
194
- - Step 16 NEVER auto-advances past `awaiting-user-greenlight` without a
195
- user signal.
196
- - Step 16 routes to Settings before sequence/start when no sender is attached.
197
- - Step 16 routes to Sequence before start when no sequenceTemplate is attached.
210
+ - Step 16 may move the watched UI through Settings, Sequence, and Send, but it
211
+ NEVER transitions to `running` or calls `start_campaign` without a user signal.
212
+ - Step 16 routes to Settings before sender attach.
213
+ - Step 16 routes to Sequence after sender attach and before sequence attach.
214
+ - Step 16 routes to Send after the recommended sequence is attached.
198
215
  - Prefer `attach_recommended_sequence`; use `attach_sequence` only for an
199
216
  explicitly custom cadence.
200
217
  - Bulk-approve in the Claude greenlight path uses the EXISTING
@@ -61,10 +61,14 @@ Step 15 — observe messaging
61
61
 
62
62
  Step 16 — awaiting-user-greenlight
63
63
  get_campaign + list_senders
64
- if no sender attached: surface campaign settings link and STOP
65
- if sender attached: attach_recommended_sequence({ campaignId }) # tier-aware: premium/SN -> If Open Profile->INMAIL_OPEN, else INVITE->accepted->DM
66
- re-surface watchUrl + review-batch orientation
67
- STOP. DO NOT call start_campaign. DO NOT auto-advance currentStep.
64
+ update_campaign(currentStep=settings) + orient the watch link to Settings
65
+ if no connected sender exists: explain sender setup + Slack reply review, surface campaign settings link, and STOP
66
+ ask the user which connected sender to attach; in explicit UAT safe mode only, use the safe mock sender
67
+ update_campaign(senderIds=[selectedSenderId], currentStep=sequence)
68
+ attach_recommended_sequence({ campaignId, currentStep: "send" }) # tier-aware: premium/SN -> If Open Profile->INMAIL_OPEN, else INVITE->accepted->DM
69
+ if the attach response did not move the UI: update_campaign(currentStep=send)
70
+ re-surface watchUrl + review-batch orientation + final launch choices
71
+ STOP. DO NOT call start_campaign. DO NOT move to running without explicit launch greenlight.
68
72
  ```
69
73
 
70
74
  **Prefer `attach_recommended_sequence` over `attach_sequence` in the
@@ -136,7 +140,8 @@ reuse the v1 `create-campaign` watch-mode pattern verbatim.
136
140
 
137
141
  Resume currentStep names covered by this tail: `"auto-execute-leads"`,
138
142
  `"validate-sample"`, `"auto-execute-messaging"`,
139
- `"awaiting-user-greenlight"`, and `"running"`. New mint-early runs normally
143
+ `"awaiting-user-greenlight"`, `"settings"`, `"sequence"`, `"send"`, and
144
+ `"running"`. New mint-early runs normally
140
145
  enter Step 13 from `"confirm-lead-list"`; the `"auto-execute-leads"` string is
141
146
  kept for compatibility resumes.
142
147
 
@@ -308,6 +313,13 @@ awaiting-user-greenlight, or start-campaign. It must hand off as
308
313
  `sample_revision_required` with the observed counts so the user can decide
309
314
  whether the source or filter should change.
310
315
 
316
+ If the same source lane has already failed after a revision, do not present
317
+ another same-source revision as the recommended/default next action. Recommend
318
+ the strongest fallback lane first (for example, Sales Nav after repeated
319
+ Signals underfloor results), then offer revise-filter only if the imported rows
320
+ look close to ICP but the rubric is too strict. This prevents customer-visible
321
+ loops where the agent keeps asking to retry the same weak source.
322
+
311
323
  When the sample passes the projected-pass floor, call
312
324
  `update_campaign({ campaignId, currentStep: "auto-execute-messaging" })`
313
325
  and orient the user that messaging will complete for the review batch only.
@@ -407,7 +419,8 @@ row. Step 15 does not stall on critique.
407
419
 
408
420
  ## Step 16: awaiting-user-greenlight
409
421
 
410
- Entered on `CampaignOffer.currentStep === "awaiting-user-greenlight"`.
422
+ Entered on `CampaignOffer.currentStep === "awaiting-user-greenlight"` or a
423
+ final-handoff UI step (`"settings"`, `"sequence"`, or `"send"`).
411
424
  Full contract lives in `references/final-handoff-contract.md`.
412
425
 
413
426
  Shape:
@@ -415,19 +428,37 @@ Shape:
415
428
  1. Call `get_campaign({ campaignId })` and inspect sender/sequence state.
416
429
  2. Call `list_senders()` so you can surface connected sender options if the
417
430
  campaign has no attached sender.
418
- 3. If the campaign has no attached sender, surface a direct settings link:
419
- `/campaign-builder/{campaignId}/settings?mode=claude`. Tell the user to attach
420
- a sender in Settings, then return here. STOP before sequence attach/start.
421
- 4. If a sender is attached, call `attach_recommended_sequence({ campaignId })`
422
- (bind the tier-recommended sequence to the campaign).
423
- 5. Re-surface the `watchUrl` using `references/watch-link-handoff.md`.
424
- 6. Surface the `handoff.orientation` string from `auto-execute.yaml`
425
- alongside the link.
426
- 7. STOP. Do NOT call `start_campaign`. Do NOT auto-advance
427
- `currentStep`. The autonomous tail ends here.
428
- 8. Make the credit boundary explicit in the handoff: only the first review
429
- batch has been enriched/messaged; expanding to more leads requires a
430
- separate user instruction.
431
+ 3. Call `update_campaign({ campaignId, currentStep: "settings" })`, then use
432
+ `get_campaign_navigation_state` when available to confirm the watch link is
433
+ visibly on Settings.
434
+ 4. Explain why the sender matters: Sellable needs a connected LinkedIn sender
435
+ before anything can send. Explain Slack reply review before launch: replies
436
+ and approvals need a place the team will actually monitor, so Slack should be
437
+ connected or intentionally skipped before launch.
438
+ 5. If no connected sender exists, surface a direct Settings link:
439
+ `/campaign-builder/{campaignId}/settings?mode=claude`. Tell the user to
440
+ connect a sender there, then return here. STOP before sequence attach/start.
441
+ 6. If connected senders exist but none is attached, ask the user which connected
442
+ sender to attach. Attach only after the user chooses. In explicit UAT safe
443
+ mode, use only the safe mock sender; never pick a real sender.
444
+ 7. Call `update_campaign({ campaignId, senderIds: [selectedSenderId],
445
+ currentStep: "sequence" })` to attach the sender through the v3 senders
446
+ route and orient the watch link to Sequence.
447
+ 8. Call `attach_recommended_sequence({ campaignId, currentStep: "send" })`
448
+ (bind the tier-recommended sequence to the campaign). If the tool response
449
+ does not persist `currentStep: "send"`, call
450
+ `update_campaign({ campaignId, currentStep: "send" })`.
451
+ 9. Re-surface the `watchUrl` using `references/watch-link-handoff.md`.
452
+ 10. Surface the `handoff.orientation` string from `auto-execute.yaml`
453
+ alongside the link.
454
+ 11. Ask the final launch greenlight with the structured question function:
455
+ Start campaign, Review campaign first, or Pause here.
456
+ 12. STOP unless the user explicitly chooses Start campaign. Do NOT call
457
+ `start_campaign` from Step 16 itself; that belongs only to the Claude
458
+ greenlight path. The autonomous tail ends here.
459
+ 13. Make the credit boundary explicit in the handoff: only the first review
460
+ batch has been enriched/messaged; expanding to more leads requires a
461
+ separate user instruction.
431
462
 
432
463
  Two equally valid greenlight channels take Step 16 into a running
433
464
  campaign:
@@ -441,9 +472,9 @@ campaign:
441
472
  sequence is attached, `attach_recommended_sequence({ campaignId })`, (c)
442
473
  bulk-approve queued messages via the EXISTING endpoint
443
474
  `POST /api/v3/workflow-tables/cells/approve-batch` (do NOT invent a
444
- new tool/endpoint), (d) `start_campaign({ campaignId })`, (e)
445
- `update_campaign({ campaignId, currentStep: "running" })`, (f)
446
- re-surface `watchUrl` plus a "campaign is live" confirmation.
475
+ new tool/endpoint), (d) `start_campaign({ campaignId })`, which persists
476
+ `currentStep: "running"`, (e) re-surface `watchUrl` plus a "campaign is live"
477
+ confirmation.
447
478
 
448
479
  A Claude greenlight on an already-running campaign is a no-op
449
480
  confirmation, NOT a duplicate start. Detect via `get_campaign` before