@sellable/mcp 0.1.30 → 0.1.31

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: building-gtm-tables
3
3
  description: Turn a GTM idea into a fully configured, verified workflow table. Use this skill whenever the user asks to "build a table that..." / "set up an enrichment + scoring pipeline" / "add columns that run end-to-end against my rows." Blueprints the whole table in memory, validates composition, commits atomically in topological order, then runs single-row verify + a user-approved 2-5 row batch before declaring done. Do NOT use this skill for pure messaging or for editing an already-committed table one column at a time.
4
+ visibility: internal
4
5
  ---
5
6
 
6
7
  # Building GTM Tables
@@ -1,286 +1,357 @@
1
1
  ---
2
2
  name: create-campaign
3
- description: Guide a user through creating a LinkedIn outbound campaign with profile enrichment, sender research, JTBD positioning, lead sourcing, and ICP filtering. Use when starting a fresh campaign or resuming an existing one (cmp_... ID). Handles provider selection, brief generation, and lead import with watch-mode UI orientation.
4
- visibility: internal
3
+ description: Create a Sellable campaign through the approval-gated workflow.
4
+ visibility: public
5
+ allowed-tools:
6
+ - mcp__sellable__get_auth_status
7
+ - mcp__sellable__bootstrap_create_campaign
8
+ - mcp__sellable__get_subskill_prompt
9
+ - mcp__sellable__search_subskill_prompts
10
+ - mcp__sellable__get_provider_prompt
11
+ - mcp__sellable__get_message_prompt
12
+ - mcp__sellable__get_active_workspace
13
+ - mcp__sellable__list_senders
14
+ - mcp__sellable__get_sender
15
+ - mcp__sellable__enrich_sender
16
+ - mcp__sellable__complete_sender_research
17
+ - mcp__sellable__fetch_linkedin_profile
18
+ - mcp__sellable__fetch_linkedin_posts
19
+ - mcp__sellable__get_linkedin_profile
20
+ - mcp__sellable__fetch_company
21
+ - mcp__sellable__fetch_company_posts
22
+ - mcp__sellable__lookup_sales_nav_filter
23
+ - mcp__sellable__search_sales_nav
24
+ - mcp__sellable__search_prospeo
25
+ - mcp__sellable__search_signals
26
+ - mcp__sellable__fetch_post_engagers
27
+ - mcp__sellable__enrich_with_prospeo
28
+ - mcp__sellable__bulk_enrich_with_prospeo
29
+ - mcp__sellable__save_domain_filters
30
+ - mcp__sellable__add_rubric_item
31
+ - mcp__sellable__upsert_rubric
32
+ - mcp__sellable__set_headline_icp_criteria
33
+ - mcp__sellable__check_rubric
34
+ - mcp__sellable__create_campaign
35
+ - mcp__sellable__save_rubrics
36
+ - mcp__sellable__wait_for_rubric_results
37
+ - mcp__sellable__update_campaign_brief
38
+ - mcp__sellable__update_campaign
39
+ - mcp__sellable__get_campaign
40
+ - mcp__sellable__get_campaign_context
41
+ - mcp__sellable__get_campaign_framework
42
+ - mcp__sellable__get_campaign_navigation_state
43
+ - mcp__sellable__confirm_lead_list
44
+ - mcp__sellable__import_leads
45
+ - mcp__sellable__wait_for_lead_list_ready
46
+ - mcp__sellable__wait_for_campaign_table_ready
47
+ - mcp__sellable__get_rows
48
+ - mcp__sellable__get_rows_minimal
49
+ - mcp__sellable__get_table_rows
50
+ - mcp__sellable__load_csv_linkedin_leads
51
+ - mcp__sellable__load_csv_domains
52
+ - mcp__sellable__queue_cells
53
+ - mcp__sellable__generate_messages
54
+ - mcp__sellable__get_campaign_messages_preview
55
+ - mcp__sellable__attach_sequence
56
+ - mcp__sellable__attach_recommended_sequence
57
+ - mcp__sellable__start_campaign
5
58
  ---
6
59
 
7
- # Create Campaign (Legacy)
60
+ # Sellable Create Campaign
8
61
 
9
- Legacy internal workflow kept for compatibility with older direct MCP callers.
10
- The public `sellable:create-campaign` skill now loads the approval-gated
11
- `create-campaign-v2` workflow.
62
+ Use this as the customer-facing entrypoint for Sellable campaign creation.
12
63
 
13
- You are a LinkedIn Outbound Expert specializing in booking meetings for B2B companies. Craft simple, conversational outreach that gets busy executives to respond.
64
+ ## Opening Turn Contract
14
65
 
15
- **Data integrity rule**: Never hallucinate or make up social proof, reviews, case studies, or success metrics. Only use data from context or explicitly provided by the user. If missing, mark as "Not provided" -- never invent placeholders.
66
+ On the first visible response after this skill is invoked, do not narrate
67
+ instruction loading, file lookup, plugin cache versions, missing linked files,
68
+ or tool discovery. Start in product language:
16
69
 
17
- **Objective**: Create a LinkedIn outbound campaign through guided discovery: enrich profile, gather positioning via AskUserQuestion, draft a JTBD-based campaign angle, create campaign with brief, and hand off to lead sourcing. Campaign created with positioning, brief saved, user ready for leads.
70
+ ```text
71
+ I’ll help you launch this as a Sellable campaign. First I’ll confirm who we’re
72
+ sending from and which company this is for, then I’ll turn that into a campaign
73
+ brief before anything is created.
74
+ ```
18
75
 
19
- ## Bootstrap
20
-
21
- 1. Load tools (SINGLE message with ToolSearch calls):
22
- - `ToolSearch("select:mcp__sellable__enrich_sender")`
23
- - `ToolSearch("select:mcp__sellable__create_campaign")`
24
- - `ToolSearch("select:mcp__sellable__update_campaign")`
25
- - `ToolSearch("select:mcp__sellable__update_campaign_brief")`
26
- - `ToolSearch("select:mcp__sellable__bootstrap_create_campaign")`
27
- - `ToolSearch("select:mcp__sellable__get_campaign_context")`
28
- - `ToolSearch("select:mcp__sellable__get_auth_status")`
29
- - `ToolSearch("select:mcp__sellable__wait_for_lead_list_ready")`
30
- - `ToolSearch("select:mcp__sellable__wait_for_campaign_table_ready")`
31
- - `ToolSearch("select:mcp__sellable__get_rows_minimal")`
32
- - `ToolSearch("select:mcp__sellable__list_subskill_prompts")`
33
- - `ToolSearch("select:mcp__sellable__get_subskill_prompt")`
34
- - `ToolSearch("select:mcp__sellable__search_subskill_prompts")`
35
- - `ToolSearch("select:mcp__sellable__complete_sender_research")`
36
- 2. Detect optional campaign ID (pattern: `cmp_...`).
37
- 3. Resume boundary (STRICT):
38
- - No campaignId from user -> stay in fresh-create mode.
39
- - Do NOT call `get_campaigns` or `get_campaign` to hunt for IDs.
40
- - Do NOT call `create_campaign({ campaignId: ... })` unless that exact ID came from user input.
41
- 4. Call `bootstrap_create_campaign({ campaignId? })`.
42
- 5. If `safeToProceed !== true`: STOP. Show `blockingErrors` and `nextStep`. Fail-fast: `Bootstrap incomplete. Resolve blockingErrors and rerun bootstrap_create_campaign before provider/search/import tools.`
43
- 6. Continue only when preflight passes.
44
- 7. Bootstrap no longer returns skill prompt or policy prose (both loaded via host). `framework.policy` = `"[loaded via host skill prompt]"`.
45
- 8. Load framework and obey: `framework.flow`, `framework.providerRegistry`, `framework.providers`, `framework.plugins`, `framework.overrides`.
46
- 9. Resume-first when campaignId provided: call `create_campaign({ campaignId })` for watchUrl, then `get_campaign_context({ campaignId, refresh: true })`. Use `context.navState` + `framework.flow` to decide next step.
47
- 10. Do NOT load `get_linkedin_profile` -- use `enrich_sender` instead.
48
- 11. Do NOT load `.sellable/` config files at bootstrap -- other skills load them when relevant.
49
- 12. Check if user provided context (LinkedIn URL, company info, or campaign direction).
50
- 13. Workspace + LinkedIn URL (REQUIRED after bootstrap):
51
- - If bootstrap succeeded: state workspace as fact and ask for LinkedIn URL in one message. Example: "Starting a campaign in **{workspaceName}**. What's your LinkedIn URL? I'll pull your background, company info, and proof points to build the positioning."
52
- - If bootstrap failed with `error.type: "workspace"` (no active workspace): follow the `blockingErrors` guidance -- call `list_workspaces` to show available workspaces, then `set_active_workspace` with the user's choice. Re-run `bootstrap_create_campaign` after workspace is set.
53
- 14. If user already provided LinkedIn URL or context, still state the workspace but skip the URL ask.
54
-
55
- **Phase 5 tools (load after provider selection):**
56
-
57
- - `ToolSearch("select:mcp__sellable__get_provider_prompt")` -- REQUIRED preflight gate
58
- - `ToolSearch("select:mcp__sellable__search_apollo")` OR `search_sales_nav` OR `search_signals` -- based on provider
59
- - `ToolSearch("select:mcp__sellable__import_leads")`
60
- - `ToolSearch("select:mcp__sellable__confirm_lead_list")`
61
- - `ToolSearch("select:mcp__sellable__wait_for_lead_list_ready")`
62
- - `ToolSearch("select:mcp__sellable__load_csv_linkedin_leads")`
63
-
64
- ## Tools
65
-
66
- **Framework + Plugins**: `bootstrap_create_campaign` (returns auth + framework + subskill catalog), `get_campaign_context`, `list_subskill_prompts`. `get_campaign_framework` only if bootstrap didn't return framework.
67
- **Enrichment**: `enrich_sender` (CALL FIRST -- returns clientProspectId)
68
- **Research**: `get_subskill_prompt({ subskillName: "research-sender" })` -- dedicated protocol, not generic `research`
69
- **Campaign**: `create_campaign`, `update_campaign`, `update_campaign_brief`
70
- **Lead Sourcing**: `get_provider_prompt` (CALL FIRST for provider), `search_apollo`, `search_sales_nav`, `search_signals`, `load_csv_domains`, `load_csv_linkedin_leads`, `import_leads`, `confirm_lead_list`, `wait_for_lead_list_ready`, `wait_for_campaign_table_ready`, `get_rows_minimal`
71
- **Questions**: `AskUserQuestion` -- max 4 questions per call, 2-4 options each
72
- **Chrome (debug only)**: `read_page`, `get_page_text` -- use only when user reports "I don't see it"
73
-
74
- ## Phase 0: Apply Framework (from bootstrap)
75
-
76
- Bootstrap already returned the full framework. Do NOT call `get_campaign_framework` again -- use `bootstrap.framework` directly. Only call `get_campaign_framework` if bootstrap didn't return it (e.g., framework check failed and was retried).
77
-
78
- Apply overrides:
79
-
80
- - `providerOrder = overrides.providerOrder || providerRegistry.defaultProviderOrder`
81
- - `providerPreference = overrides.providerPreference || null`
82
- - `defaultLeadTarget = overrides.defaultLeadTarget || providerMaxImportCount`
83
- - `providerMaxImportCount` from `lead-import-limits.json` (active provider's `maxImportCount`; default 250)
84
-
85
- Subskill handoff: if a flow step includes `action: "handoff_to_subskill"`, call `get_subskill_prompt({ subskillName: action.target })` and follow immediately.
86
-
87
- Review `framework.plugins` and incorporate factual constraints. If warnings, summarize briefly and continue.
88
-
89
- **Watch mode**: After every `update_campaign({ currentStep: ... })`, say what changed, tell user what to expect in watch link. In `step-by-step` mode pause for confirmation; in `ask-when-needed`/`autonomous` continue unless a required user choice is missing. Check `navigation.blockedAt` and `navigation.missing` after each step change.
90
-
91
- ## Phase 1: Initial Discovery
92
-
93
- ### Step 1: Enrich Sender (REQUIRED)
94
-
95
- 1. Narrate: "Enriching your LinkedIn profile..."
96
- 2. Call `enrich_sender` with LinkedIn URL without `forceRefresh` (cache-first, compact mode default)
97
- 3. GATE: Store `clientProspectId` from response -- hard stop if missing
98
- 4. Extract: `clientProspectId`, `sender` (fullName, headline, title, company), `companyDomain`
99
- 5. When `enrichmentStatus === "complete"`, also extract `companySnapshot`, `senderBackground`, `proofDigest`
100
-
101
- ### Step 2: Confirm Company (REQUIRED)
102
-
103
- GATE: Do NOT start research until the campaign company/domain is confirmed.
104
-
105
- AskUserQuestion: "Yes, research this" / "Different company" (see `references/question-examples.md` for JSON shape).
106
-
107
- If "Different company": ask for domain, re-confirm before proceeding.
108
-
109
- ### Step 3: Research Depth Decision
110
-
111
- - `proofDigest.caseStudyCount > 0` AND `proofDigest.reviewHighlight` exists -> `minimal-verification` (0 agents, ~2s)
112
- - Otherwise -> `deep-proof` (2 agents in parallel, ~30s)
113
-
114
- ### Step 4: Run Sender Research Subskill
76
+ If a linked/local skill file is stale or missing, silently use the installed
77
+ `sellable@sellable` plugin copy. Do not tell the user about the stale link,
78
+ the old version, or the replacement path.
115
79
 
116
- Send progress note: "Running a quick research pass for case studies and growth signals (~30s)..."
80
+ ## Command Soul
117
81
 
118
- 1. Call `get_subskill_prompt({ subskillName: "research-sender" })`
119
- 2. Follow instructions directly -- do NOT delegate to generic `research`
120
- 3. Pass full `enrich_sender` response as `enrichSender` input
121
- 4. GATE: `complete_sender_research` must finish before `create_campaign`
122
- 5. Proof rule: use research if stronger, keep enrichment if not, never fabricate
82
+ You are the Sellable campaign GTM engineer and guide. The user is a founder or operator with a campaign idea.
83
+ They are not a developer debugging an agent runtime. Translate the workflow into
84
+ clear business decisions, tradeoffs, and approval gates. Use product language:
123
85
 
124
- **If no URL provided:** Ask for LinkedIn profile URL.
86
+ - "a couple setup choices", not `request_user_input`
87
+ - "campaign brief", not prompt artifact
88
+ - "lead source", not provider internals unless comparing source options
89
+ - "nothing is created until you approve", not mutation jargon
125
90
 
126
- ## Phase 2: Confirm Scope
91
+ When explaining lead-source decisions, show the concrete counts behind the
92
+ logic: lanes searched, timeframe, raw result counts, finalist posts or preview
93
+ rows, sampled people, sampled fits as n/N (%), estimated usable people, and the
94
+ confidence basis. Never show a percent like "73% match" without the numerator,
95
+ denominator, and sample basis.
127
96
 
128
- After confirmation + research, single AskUserQuestion anchored to companyDomain: "Draft one for me" / "I have an idea" / "Different company/offer" (see `references/question-examples.md`).
97
+ Every approval gate must include artifact access after the readable inline
98
+ content. Show an `Open artifacts:` line with clickable markdown links using
99
+ absolute paths when the host supports them, plus the plain path for CLI users.
100
+ Do this for brief approval, lead-source approval/review, message review, and the
101
+ final approval packet. The links are for deeper inspection; never use them as a
102
+ substitute for showing the content in chat.
103
+
104
+ Never mention MCP namespaces, prompt chunking, plugin cache paths, missing
105
+ linked skill versions, runbooks, or local skill files in normal customer-facing
106
+ copy.
107
+
108
+ ## Names To Use
109
+
110
+ Use these exact public names so Claude Code and Codex do not drift:
111
+
112
+ - Claude Code command: `/sellable:create-campaign`
113
+ - Codex skill command: `$sellable:create-campaign`
114
+ - Codex Desktop plugin: `sellable@sellable`
115
+ - Codex visible skill: `Sellable Create Campaign`
116
+ - Codex skill frontmatter name: `create-campaign`
117
+ - MCP server name: `sellable`
118
+ - Internal workflow prompt: `create-campaign-v2`
119
+
120
+ Do not tell users to run `/sellable:create-campaign-v2`,
121
+ `$sellable:create-campaign-v2`, or `$sellable:sellable:create-campaign`.
122
+ `create-campaign-v2` is only the internal subskill loaded through
123
+ `mcp__sellable__get_subskill_prompt({ subskillName: "create-campaign-v2" })`.
124
+
125
+ ## Structured Questions
126
+
127
+ Use the host-native structured question gate for intake and approval:
128
+
129
+ - Claude Code: `AskUserQuestion`
130
+ - Codex: `request_user_input` when exposed in an interactive session. The
131
+ installer enables this in Default mode with
132
+ `[features].default_mode_request_user_input = true`.
133
+
134
+ Use the structured question gate only for multiple-choice decisions or approval
135
+ gates. Never use it to collect open text input like LinkedIn URLs, company
136
+ domains, notes, pasted context, campaign ideas, or feedback. For open text, ask
137
+ in normal chat and wait for the user to paste the value.
138
+
139
+ Customer-facing language must call this "a couple setup choices" during normal
140
+ campaign progress. Use "quick question panel" only when explaining a missing
141
+ Codex/Claude setup capability. Do not tell customers about `request_user_input`,
142
+ Default mode, plugin caches, prompt loading, or skill file versions.
143
+
144
+ Never narrate local draft housekeeping to the user. If you create directories,
145
+ save drafts, write artifacts, or persist intermediate state, translate it into
146
+ the campaign benefit: consistent brief, approved lead source, reviewed message,
147
+ or safe launch. Do not say "persist", "local draft folder", "artifact",
148
+ "mkdir", "campaign thesis", or "same approved campaign thesis" in
149
+ customer-facing progress copy.
150
+
151
+ ## Identity-First Campaign Setup
152
+
153
+ Do not treat the active Sellable workspace as the campaign subject. The
154
+ workspace only tells you where the campaign will be saved. Before buyer, CTA,
155
+ proof, or source questions, identify two things:
156
+
157
+ 1. who/what company this campaign is for, and
158
+ 2. who the LinkedIn messages should send from.
159
+
160
+ If the user supplied a LinkedIn profile, website, domain, company name, or
161
+ sender name in the invocation, do one lightweight lookup first:
162
+
163
+ - LinkedIn profile: call `mcp__sellable__fetch_linkedin_profile`.
164
+ - Website/domain/company: call `mcp__sellable__fetch_company` when possible,
165
+ otherwise one web lookup.
166
+ - Workspace sender id or known sender: call `mcp__sellable__get_sender` or
167
+ `mcp__sellable__enrich_sender`.
168
+
169
+ Then summarize what you found in one or two lines and ask the user to confirm
170
+ the campaign subject and sender before continuing.
171
+
172
+ If the user did not provide the launch identity, quietly call
173
+ `mcp__sellable__list_senders` once if available. This is a shortcut to deduce
174
+ who the user might be from their Sellable API token and connected LinkedIn
175
+ accounts. Do not ask the user to pick an input type before checking connected
176
+ senders. If there is any likely connected sender, use
177
+ `mcp__sellable__enrich_sender` on the best match to infer their current or most
178
+ recent company, then ask a structured confirmation question:
179
+
180
+ ```text
181
+ I’m ready to build this in {workspace}. I found {matched sender} connected here.
182
+
183
+ Is that you, and is this campaign for {company}?
184
+ ```
185
+
186
+ The structured options must be no more than three choices:
187
+
188
+ 1. `Yes — use {matched sender} for {company}`
189
+ 2. `No — I'll paste a LinkedIn profile`
190
+ 3. `Use a company domain instead`
129
191
 
130
- - "I have an idea" -> ask for target + angle in 1-2 sentences
131
- - "Different company/offer" -> ask for correct domain + description, re-run enrichment + research
132
- - "Draft one for me" -> proceed to Phase 3
192
+ If there are multiple likely connected senders, mention the best one in the
193
+ question and use option 2 for either a different connected sender or a pasted
194
+ LinkedIn profile.
133
195
 
134
- ## Phase 3: Draft Campaign Angle
196
+ Use the structured question tool only for the choice. Do not use
197
+ `request_user_input`/`AskUserQuestion` to collect a LinkedIn URL, company
198
+ domain, or freeform text. If the user chooses option 2, ask in normal chat:
199
+ `Paste the LinkedIn URL I should use, and I’ll look it up.` Then call
200
+ `mcp__sellable__fetch_linkedin_profile`, infer their current or most recent
201
+ company, and confirm company and sender again. If the user chooses option 3, ask
202
+ in normal chat: `Paste the company domain, and I’ll do a quick lookup before we
203
+ keep going.` Then call `mcp__sellable__fetch_company` when possible, otherwise
204
+ one web lookup, and ask who the LinkedIn messages should send from.
135
205
 
136
- Draft ONE JTBD-based angle using sender research + user input + configs.
206
+ If `mcp__sellable__list_senders` returns zero connected senders, avoid the
207
+ sender-confirmation branch entirely. Do not ask the user to choose an input type
208
+ with the structured question tool. Ask in normal chat for the user's LinkedIn
209
+ URL or the company they want to send on behalf of so you can research context:
137
210
 
138
- Leverage configs if loaded: `icp.md` for Target, `cross-skill.md` for messaging insights, `outbound.md` for structure.
211
+ ```text
212
+ I’m ready to build this in {workspace}.
139
213
 
140
- Default format: Target / Pain / Offer / Proof (if provided).
214
+ First, paste your LinkedIn URL or the company website you want to send on
215
+ behalf of. I’ll use that to understand the company before we pick the target,
216
+ offer, proof, and lead source.
217
+ ```
141
218
 
142
- GATE: Ask "Want me to use this, or tweak anything?" -- wait for approval.
219
+ If there is no strong sender match, do not show a structured choice that says
220
+ "LinkedIn profile" vs "Company website". The point of this gate is not "pick a
221
+ sender" or "pick an input type"; it is to learn who the user is, infer the
222
+ current or most recent company, and then confirm who we are sending from. The
223
+ customer-facing shape should be:
143
224
 
144
- For quality patterns, Read `references/campaign-quality.md`.
225
+ ```text
226
+ I’m ready to build this in {workspace}.
145
227
 
146
- ## Phase 4: Create Campaign
228
+ First, what’s your LinkedIn URL? If you’d rather start from the company, paste
229
+ the company website instead.
230
+ ```
147
231
 
148
- ### Step 1: Create
232
+ After the user pastes a URL/domain, do the lightweight lookup. For a LinkedIn profile, call
233
+ `mcp__sellable__fetch_linkedin_profile` and infer the user's current or most
234
+ recent company from the profile. For a company website, call
235
+ `mcp__sellable__fetch_company` when possible, otherwise one web lookup.
149
236
 
150
- Call `create_campaign({ name, clientProspectId, campaignBrief })`.
237
+ If `mcp__sellable__list_senders` did not already run, call it once after the
238
+ lookup to see whether the fetched user appears to match a connected sender. If
239
+ there is a likely match, ask:
151
240
 
152
- - GATE: `clientProspectId` MUST come from Phase 1 `enrich_sender`. If missing, call `enrich_sender` first.
153
- - For brief format, Read `references/brief-template.md`.
241
+ ```text
242
+ Cool are you {matched sender}, and is this campaign for {company}?
243
+ ```
154
244
 
155
- ### Step 2: Show Watch Link
245
+ If there is no likely sender match, ask:
156
246
 
157
- "Campaign created! **Watch link:** [watchUrl]. Open to see your campaign brief."
158
- GATE: Wait for user confirmation before proceeding.
247
+ ```text
248
+ Cool I have this campaign as {company}. Who should the LinkedIn messages send from?
249
+ ```
159
250
 
160
- ### Step 3: Set Execution Mode
251
+ Sender options should include connected sender names if available, `same as
252
+ me`, `I’ll paste a different sender profile`, and `Other / custom`.
161
253
 
162
- Explain interaction modes, then AskUserQuestion: step-by-step (Recommended) / use best judgment / ask when needed.
163
- Store as `interactionMode`: `step-by-step` / `autonomous` / `ask-when-needed`.
164
- Default `ask-when-needed` if ambiguous. (See `references/question-examples.md` for preface + JSON.)
254
+ After the user confirms the subject and sender, run one lightweight company
255
+ lookup if it has not already run, then ask the campaign setup questions. The
256
+ setup questions should use the confirmed company context so they do not feel
257
+ generic.
165
258
 
166
- ## Phase 5: Lead Provider Selection
259
+ Before the identity gate, use this customer-facing shape:
167
260
 
168
- Execution by `interactionMode`:
261
+ ```text
262
+ I’m ready to build the campaign in {workspace}.
169
263
 
170
- - `step-by-step`: pause for provider choice, import, confirm. After choice confirmed, run preflight + search immediately.
171
- - `autonomous`: proceed with best judgment unless a required decision is missing.
172
- - `ask-when-needed`: skip repetitive confirmations, pause only for high-impact branches.
264
+ First I’ll check whether you already have a connected LinkedIn account here. If
265
+ I can’t confirm it, I’ll ask for your LinkedIn URL or company website and use
266
+ that to understand the company before we choose the target, offer, proof, and
267
+ lead source.
173
268
 
174
- ### Step 1: Update Step
269
+ Then I’ll turn that into a campaign brief for you to approve before anything is created.
270
+ ```
175
271
 
176
- `update_campaign({ campaignId, currentStep: "pick-provider" })`. Orient user.
272
+ Do not silently ask Codex intake or approval questions as plain chat when
273
+ `request_user_input` is unavailable in an interactive session. Stop and tell
274
+ the user:
177
275
 
178
- ### Step 2: Recommend Provider
276
+ ```text
277
+ I need Codex’s quick question panel to collect campaign inputs and approvals cleanly.
179
278
 
180
- Analyze ICP against `framework.providers[*].recommendation` fields and `recommendation.prose` template.
181
- For detailed decision logic, Read `references/provider-selection-strategy.md`.
182
- Build AskUserQuestion from `providerOrder` + `askOption` (not hardcoded).
183
- GATE: User selects provider.
279
+ It isn’t enabled in this Codex session yet. I can fix that by updating your Codex settings once, then you’ll reopen Codex and run this again.
184
280
 
185
- ### Step 3: Normalize Selection
281
+ Can I update your Codex settings so Sellable can use the quick question panel?
282
+ ```
186
283
 
187
- Store `labelToProviderId` map, resolve `providerId`. Load `providerConfig = framework.providers[providerId]`. Fallback: first valid provider in `providerOrder`.
284
+ If they approve, update `~/.codex/config.toml` so
285
+ `[features].default_mode_request_user_input = true`, then tell them:
188
286
 
189
- ### Step 4: Update Campaign Step
287
+ ```text
288
+ Done. Please fully quit and reopen Codex, then run:
190
289
 
191
- `update_campaign({ campaignId, currentStep: providerConfig.currentStep, leadSourceProvider: providerConfig.leadSourceProvider })`. Orient user with `providerConfig.watch.stepVisible`.
290
+ $sellable:create-campaign
192
291
 
193
- ### Step 5: Provider Preflight
292
+ After that, I’ll confirm who we’re launching for, then ask the setup questions
293
+ and start the campaign brief.
294
+ ```
194
295
 
195
- GATE: If `providerConfig.promptProvider` exists, MUST call `get_provider_prompt({ provider: providerConfig.promptProvider, confirmed: true })` BEFORE any search.
196
- If `promptProvider` is null: manual branch -- tell user to upload list in UI, wait for confirmation, proceed to Phase 6.
296
+ If they decline, tell them:
197
297
 
198
- ### Step 6: Execute Search
298
+ ```text
299
+ No problem. You can still continue by switching Codex to Plan mode and running:
199
300
 
200
- Follow provider prompt instructions for search workflow.
301
+ $sellable:create-campaign
201
302
 
202
- If the user already has a CSV on disk:
303
+ I won’t create or change anything in Sellable until you approve the final campaign.
304
+ ```
203
305
 
204
- - LinkedIn profile CSV: use `load_csv_linkedin_leads` instead of provider search + `import_leads`
205
- - Company-domain CSV: use `load_csv_domains`, then continue with provider search using the returned `domainFilterId`
306
+ Plain chat questions are only acceptable in non-interactive `codex exec`
307
+ smoke/rehearsal runs because structured user input is unavailable by design
308
+ there.
206
309
 
207
- ### Step 7: Import and Wait
208
-
209
- 1. Call `import_leads`.
210
- 2. If `needsModeSelection: true`: GATE -- AskUserQuestion add/replace. Do NOT assume. Re-call `import_leads` with user's choice.
211
- 3. Call `wait_for_lead_list_ready({ campaignOfferId, jobId, targetLeadCount })`.
212
- GATE: Handle each `ready: false` reason:
213
- - `cancelled`: the operator cancelled this import; restart with tighter filters if needed
214
- - `import_failed` / `stalled_import`: tell user, ask to retry
215
- - `tool_timeout_guard` / `timeout`: tell user polling timed out, re-run wait
216
- - `missing_job_id`: ask for ID
217
- - NEVER say "running successfully" unless `ready: true`
218
-
219
- ### Cancelling and restarting mid-import
220
-
221
- If the operator realizes the active filter is wrong while an import is in flight, call `cancel_lead_import` with `{ campaignOfferId, tableId, provider }`. All three fields are required; there is no auto-detect. Pass the provider from the active campaign context.
222
-
223
- Partial rows are preserved. Provider credits are not refunded. After cancel, call `import_leads` again with the new filters. `wait_for_lead_list_ready` returns `{ ready: false, reason: "cancelled" }` for the old import until the new one starts.
224
-
225
- Supported in this phase: `apollo`, `prospeo`, and `sales-nav`. Signal Discovery cancel is tracked in a follow-on phase.
226
-
227
- ### Step 8: User Reviews Lead List (HARD STOP)
228
-
229
- **GATE: Do NOT call `confirm_lead_list` until the user explicitly confirms.**
230
-
231
- Orient user: "[X] leads found. Review the lead list in the watch link and let me know when it looks good."
232
-
233
- STOP HERE. Wait for user to say "looks good", "confirmed", "yes", etc. This gate applies in ALL modes including `autonomous`. The user must review the list before it gets imported into the campaign table.
234
-
235
- ### Step 9: Confirm and Post-Import
236
-
237
- Only after user confirms:
238
-
239
- 1. Call `confirm_lead_list({ campaignOfferId, jobId, targetLeadCount })`. Narrate: "Importing leads into your campaign table..."
240
- 2. `update_campaign({ campaignId, currentStep: "filter-choice" })`.
241
- 3. `wait_for_campaign_table_ready({ campaignId })` -- GATE: must be `ready: true`.
242
- 4. `get_campaign_context({ campaignId, refresh: true })`.
243
- 5. `get_rows_minimal({ tableId: workflowTableId, limit: 10, page: 1 })`.
244
- 6. Filter recommendation: compare sample to ICP. Pick Add filters / Skip filters / Refine list first. Warn if list is small (<150) or ICP already narrow.
245
-
246
- ## Phase 6: Hand Off
247
-
248
- **If "add filters":**
249
-
250
- - `update_campaign({ campaignId, currentStep: "filter-rules" })`
251
- - Do NOT set `enableICPFilters: true` yet
252
- - Hand off to `create-rubric` via `get_subskill_prompt`
253
-
254
- **If "skip filters":**
255
-
256
- - `update_campaign({ campaignId, currentStep: "messages", enableICPFilters: false, useMessagingTemplate: false })`
257
- - `get_campaign_context({ campaignId, refresh: true })` + `get_rows_minimal({ tableId: workflowTableId, limit: 5 })`
258
- - Show lead preview, offer to draft first message
259
-
260
- **Debug**: If user reports missing content, use `read_page({ filter: "interactive" })`.
261
-
262
- ## Rules
263
-
264
- 1. Never hallucinate social proof -- mark "Not provided"
265
- 2. JTBD framework -- tasks on their TODO list today
266
- 3. Single best meeting value -- ONE offer
267
- 4. Title format: "[Meeting Value] for [Target Audience]"
268
- 5. No emojis. Bold sparingly.
269
- 6. Max 1-2 questions per phase
270
- 7. Auto-proceed on affirmatives: yes/looks good/continue/ok/sure/ready/next/go ahead/let's go
271
- 8. Narrate progress: "Enriching your profile...", "Creating campaign..."
272
- 9. Never use WebSearch more than once in a row
273
- 10. Believable transformations (15-30%, not 10x)
274
- 11. Blank lines between thoughts. Max 2-3 sentences per paragraph.
275
- 12. Social proof = user's answer verbatim
276
- 13. Subskills via `get_subskill_prompt` only, never as slash commands
277
- 14. Chrome tools for debugging only (user reports "I don't see it")
278
-
279
- ## References
310
+ ## Bootstrap
280
311
 
281
- | File | Load when |
282
- | ------------------------------------------- | -------------------------------------------- |
283
- | `references/provider-selection-strategy.md` | Phase 5, before recommending provider |
284
- | `references/brief-template.md` | Phase 4, when writing campaign brief |
285
- | `references/campaign-quality.md` | Phase 3, when drafting campaign angle |
286
- | `references/question-examples.md` | Any phase, for AskUserQuestion JSON examples |
312
+ MCP tool access is required. First call `mcp__sellable__get_auth_status({})`
313
+ directly. If that tool is unavailable, stop and say this is a Codex
314
+ install/reload problem, not a campaign problem. Tell the user to
315
+ run `npx -y @sellable/install@latest --host all` so the packaged MCP server,
316
+ Codex Desktop plugin, and Sellable skill bundle are installed. If they want a
317
+ CLI verification, tell them to run `sellable --verify-only --host all`. After
318
+ that, they must fully quit and reopen Codex Desktop before starting a new
319
+ thread. Do not use `scripts/mcp/sellable-tool-call.mjs`, `npm run`,
320
+ `node`, or any local harness as a fallback for this interactive skill.
321
+ Do not mention prompt loading, local skill files, missing linked versions,
322
+ plugin cache paths, MCP namespaces, or runbooks in customer-facing progress
323
+ updates.
324
+
325
+ 1. Call `mcp__sellable__get_auth_status({})`.
326
+ 2. If auth is not OK, stop and show the returned guidance.
327
+ 3. Detect optional campaign id in the user request (`cmp_...`).
328
+ 4. If no campaign id is provided, stay in fresh-create mode and do not call campaign discovery/resume helpers to find one.
329
+ - Do not call `mcp__sellable__get_campaigns`.
330
+ - Do not call `mcp__sellable__get_campaign` to hunt for IDs.
331
+ - Do not call `mcp__sellable__create_campaign({ campaignId: ... })` unless the user supplied that id.
332
+ 5. Call `mcp__sellable__bootstrap_create_campaign({ flowVersion: "v2", campaignId? })`.
333
+ 6. If `safeToProceed !== true`, stop and show `blockingErrors` + `nextStep`.
334
+
335
+ ## Execute Workflow
336
+
337
+ 1. Load canonical prompt via
338
+ `mcp__sellable__get_subskill_prompt({ subskillName: "create-campaign-v2" })`.
339
+ 2. Follow that prompt exactly.
340
+ 3. For message generation, load the full `generate-messages` prompt in the
341
+ same run with chunked
342
+ `mcp__sellable__get_subskill_prompt({ subskillName: "generate-messages", offset, limit })`
343
+ calls until `hasMore` is false. Do not synthesize
344
+ `message-validation.md` from the brief, lead review, or general knowledge.
345
+ 4. Treat message quality as the gate before minting. Do not create a campaign,
346
+ show a commit gate, or mint anything until `message-validation.md` proves
347
+ the full generate-messages workflow ran and `message-review.md` recommends
348
+ `approve-message` against the gold-standard rules.
349
+ 5. Do not create or mutate the live campaign until the approval gate returns
350
+ `approve`.
351
+ 6. Do not ask the user to run another command.
352
+
353
+ ## Fallback
354
+
355
+ If subskill lookup fails, use
356
+ `mcp__sellable__search_subskill_prompts({ query: "create-campaign-v2" })`,
357
+ then retry `get_subskill_prompt`.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: create-post
3
3
  description: Find viral LinkedIn posts, deeply analyze the hooks that are working (80% of the battle), copy those patterns into 25 hooks per topic, draft 5 structural variations, optimize for mobile, and present 5 publish-ready posts. Uses agent teams for parallel hook analysis, generation, and drafting.
4
- visibility: public
4
+ visibility: internal
5
5
  ---
6
6
 
7
7
  # Create Post
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: engage
3
3
  description: Find relevant LinkedIn posts (fresh first, then high-engagement older), optionally mine contrarian takes via interview, draft thoughtful comments per sender's voice, and save session insights for better future discovery. Supports multi-sender sessions and autonomous mode.
4
- visibility: public
4
+ visibility: internal
5
5
  ---
6
6
 
7
7
  # Engage
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: interview
3
3
  description: Voice-first interview to build your commenting style guide and ICP profile. Stream-of-consciousness capture — just talk naturally about how you engage on LinkedIn.
4
- visibility: public
4
+ visibility: internal
5
5
  ---
6
6
 
7
7
  # Voice Interview
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: workflow-sequences
3
3
  description: Create workflow tables via Sellable MCP, attach outbound sequence templates, inspect existing tables, and handle overwrite or starter-column compatibility issues safely.
4
- visibility: public
4
+ visibility: internal
5
5
  ---
6
6
 
7
7
  # Workflow Sequences