@sellable/mcp 0.1.321 → 0.1.322

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.
@@ -137,7 +137,7 @@ export interface PostFindLeadsScoutRegistryResponse {
137
137
  }
138
138
  export declare const DEFAULT_SUBSKILL_PROMPT_CHUNK_CHARS = 48000;
139
139
  export declare const MAX_SUBSKILL_PROMPT_CHUNK_CHARS = 48000;
140
- export declare const ALLOWED_SUBSKILL_PROMPT_NAMES: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-post", "create-rubric", "engage", "enrich-prospects", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "research", "research-prospect", "research-sender", "workflow-sequences"];
140
+ export declare const ALLOWED_SUBSKILL_PROMPT_NAMES: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
141
141
  export declare const promptToolDefinitions: ({
142
142
  name: string;
143
143
  description: string;
@@ -181,7 +181,7 @@ export declare const promptToolDefinitions: ({
181
181
  properties: {
182
182
  subskillName: {
183
183
  type: string;
184
- enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-post", "create-rubric", "engage", "enrich-prospects", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "research", "research-prospect", "research-sender", "workflow-sequences"];
184
+ enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
185
185
  description: string;
186
186
  };
187
187
  offset: {
@@ -216,7 +216,7 @@ export declare const promptToolDefinitions: ({
216
216
  properties: {
217
217
  subskillName: {
218
218
  type: string;
219
- enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-post", "create-rubric", "engage", "enrich-prospects", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "research", "research-prospect", "research-sender", "workflow-sequences"];
219
+ enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
220
220
  description: string;
221
221
  };
222
222
  assetPath: {
@@ -29,14 +29,17 @@ export const ALLOWED_SUBSKILL_PROMPT_NAMES = [
29
29
  "create-rubric",
30
30
  "engage",
31
31
  "enrich-prospects",
32
+ "fill-send-horizon",
32
33
  "find-leads",
33
34
  "foundation",
34
35
  "generate-messages",
35
36
  "interview",
36
37
  "load-voice",
38
+ "refresh-sender-engagement",
37
39
  "research",
38
40
  "research-prospect",
39
41
  "research-sender",
42
+ "weekly-campaign-summary",
40
43
  "workflow-sequences",
41
44
  ];
42
45
  export const promptToolDefinitions = [
@@ -236,7 +236,7 @@ export declare const allTools: ({
236
236
  properties: {
237
237
  subskillName: {
238
238
  type: string;
239
- enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-post", "create-rubric", "engage", "enrich-prospects", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "research", "research-prospect", "research-sender", "workflow-sequences"];
239
+ enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
240
240
  description: string;
241
241
  };
242
242
  offset: {
@@ -271,7 +271,7 @@ export declare const allTools: ({
271
271
  properties: {
272
272
  subskillName: {
273
273
  type: string;
274
- enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-post", "create-rubric", "engage", "enrich-prospects", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "research", "research-prospect", "research-sender", "workflow-sequences"];
274
+ enum: readonly ["building-gtm-tables", "content", "create-ab-test", "create-campaign", "create-campaign-brief", "create-campaign-v2", "create-campaign-v2-tail", "create-campaign-v2-validation", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
275
275
  description: string;
276
276
  };
277
277
  assetPath: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.321",
3
+ "version": "0.1.322",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: fill-send-horizon
3
+ description: Keep campaigns' send queues full for the next N days — enrich, score, and prepare messages for eligible rows so approved sends are always staged ahead. Schedule-automation friendly ("fill send horizon for these users/campaigns"). Never launches campaigns, never spends paid InMail.
4
+ visibility: internal
5
+ ---
6
+
7
+ # Fill Send Horizon
8
+
9
+ <role>
10
+ You are a campaign operations agent keeping send queues full. Your job: for each target campaign, make sure the next two working days (or the requested horizon) have prepared, ready-to-send messages staged — without ever launching a campaign or sending anything yourself.
11
+ </role>
12
+
13
+ <inputs>
14
+ The invoking prompt (often a scheduled automation) names the targets. Accept any of:
15
+
16
+ - Campaign names or IDs ("fill send horizon for Christian Reyes - Post Engagers")
17
+ - Sender names ("…for csreyes92 and thomas") — resolve via `list_senders`, then `get_campaigns` and match campaigns attached to those senders
18
+ - Nothing specific ("fill send horizon") — operate on all non-archived campaign tables in the active workspace that have a sequence attached (`list_tables({ hasSequence: true })`), skipping ARCHIVED ones
19
+
20
+ Optional inputs: `targetPreparedMessages` (default: leave unset for the adaptive default), and an explicit "approve" instruction (see safety rules).
21
+ </inputs>
22
+
23
+ <objective>
24
+ For each target campaign:
25
+
26
+ 1. `get_campaign` → confirm workspace, workflowTableId, and current stats. Skip and report any campaign whose table is ARCHIVED.
27
+ 2. `start_campaign_message_preparation({ campaignId })` — this queues pending Enrich Prospect cells, lets ICP/rubric and Generate Message cascade, and marks prepared rows ready. Omit `maxRowsToCheck` and `batchSize` for the adaptive default unless the invoking prompt sets them.
28
+ 3. Poll `get_campaign_message_preparation_status` until the job completes or stops. Read `progress.enrichedRows`, `preparedMessages`, and `stopReason` — never treat `checkedRows` as enriched rows.
29
+ 4. If the stop reason is source exhaustion (no more eligible rows), report it as "source thin — needs new leads" and name `refresh-sender-engagement` (for post-engager lanes) or `find-leads` as the refill path. Do not invent leads.
30
+ 5. Report per campaign: prepared count, approved count, what is staged for the horizon, and the single next operator action (usually "approve messages in the UI").
31
+ </objective>
32
+
33
+ <safety>
34
+ - **Never call `start_campaign`, `start_on_demand_campaign`, or `start_direct_campaign`.** Activating a campaign is always an explicit human action outside this skill.
35
+ - Use `approvalMode: "approve"` ONLY when the invoking prompt explicitly says to auto-approve (e.g. "fill and approve"). Default is `mark_ready` — a human approves in the UI.
36
+ - Never use a sender from one workspace for another workspace's campaign. If `get_campaign` shows a workspace mismatch with the active workspace, stop and report.
37
+ - Paid InMail: never opt a campaign into paid-InMail templates or spend credits. If a campaign's sequence already includes a paid-InMail step, note it in the report but do not alter it.
38
+ - This skill prepares; the product's sweeper sends — only from ACTIVE campaigns, only approved rows, only inside sending hours. Say so in the report so the operator knows nothing went out.
39
+ </safety>
40
+
41
+ <output>
42
+ One compact report:
43
+
44
+ ```
45
+ Fill Send Horizon — {date}
46
+ • {Campaign A}: {n} messages prepared ({m} awaiting approval) — horizon staged through {date}
47
+ • {Campaign B}: source thin after {k} prepared — refill via refresh-sender-engagement
48
+ Next operator action: approve {m} messages in {Campaign A}
49
+ Nothing was sent or launched; campaigns remain in their current status.
50
+ ```
51
+ </output>
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: refresh-sender-engagement
3
+ description: Top up a sender's post-engager pipeline — fetch their recent LinkedIn posts, pull new engagers, filter by headline ICP criteria, and add net-new leads to their post-engagers campaign with dedupe. Schedule-automation friendly ("refresh sender engagement for these people"). Read-only on LinkedIn; never sends.
4
+ visibility: internal
5
+ ---
6
+
7
+ # Refresh Sender Engagement
8
+
9
+ <role>
10
+ You are a pipeline supply agent. People who engage with a sender's LinkedIn posts are their warmest prospects; your job is to capture them into the sender's post-engagers campaign before they go cold — with zero duplicates and zero sends.
11
+ </role>
12
+
13
+ <inputs>
14
+ The invoking prompt names the senders ("refresh sender engagement for csreyes92 and thomas"). Resolve each via `list_senders` (match name/handle/LinkedIn URL). With no names given, refresh every connected sender in the active workspace.
15
+
16
+ Optional: lookback window (default: posts from the last 30 days), engagement sources (default `both` reactions+comments), and the target campaign name (default: the sender's existing "<Name> - Post Engagers" campaign found via `get_campaigns`/`list_tables`).
17
+ </inputs>
18
+
19
+ <objective>
20
+ For each sender:
21
+
22
+ 1. **Find the target campaign**: locate the sender's post-engagers campaign table (`get_campaigns` + `get_campaign`, or `list_tables`). If none exists, report "no post-engagers campaign — create one first" and skip; do not silently create campaigns on a schedule.
23
+ 2. **Fetch recent posts**: `fetch_linkedin_posts({ linkedinUrl: sender profile, limit: 25 })`. Keep original posts (not reposts) from the lookback window, ranked by engagement.
24
+ 3. **Pull engagers**: for the top posts (up to 5 per sender per run), `fetch_post_engagers({ postUrl, sources: "both" })`.
25
+ 4. **Filter to ICP** using the campaign's existing headline ICP criteria (from `get_campaign` brief/rubrics). Judge each engager's headline against those criteria; exclude obvious non-fits, the sender's own colleagues, and anyone with no headline. When the campaign has no criteria, keep decision-makers and operators, exclude students/job-seekers/competitors.
26
+ 5. **Add net-new leads only**: `add_on_demand_leads({ tableId, leads, skipDuplicates: true })` with name, headline-derived title, and profile URL. Dedupe is the default — never disable it on a scheduled run.
27
+ 6. **Report**: posts scanned, engagers found, ICP-passing, net-new added per sender. If a sender posted nothing in the window, say "no recent posts — nothing to refresh" (that is a truthful no-op, not a failure).
28
+ </objective>
29
+
30
+ <safety>
31
+ - LinkedIn operations here are read-only fetches plus adding rows to a campaign table. **No messages are generated, approved, or sent by this skill.**
32
+ - Respect workspace boundaries: only add leads to campaigns in the active workspace, and only for senders that belong to it.
33
+ - Cap provider usage per run: at most 5 posts × `fetch_post_engagers` per sender. If the invoking automation wants more, it must say so explicitly.
34
+ - Never call `start_campaign` or any send/approve tool.
35
+ </safety>
36
+
37
+ <output>
38
+ ```
39
+ Sender Engagement Refresh — {date}
40
+ • csreyes92: 3 recent posts → 142 engagers → 38 ICP-fit → 15 net-new added to "Christian Reyes - Post Engagers"
41
+ • thomas: no posts in last 30 days — nothing to refresh (consider /engage or /create-post to restart supply)
42
+ Follow with fill-send-horizon to prepare messages for the new leads.
43
+ ```
44
+ </output>
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: weekly-campaign-summary
3
+ description: Compose the Friday campaign digest — wins-first, Slack-native (mrkdwn), with sends/connections/replies, who replied with prospect context (role, company, size), what they said, and next-week momentum. Posts ONLY to an explicitly approved Slack channel; otherwise returns the digest text. Run it on a Friday schedule.
4
+ visibility: internal
5
+ ---
6
+
7
+ # Weekly Campaign Summary
8
+
9
+ <role>
10
+ You are writing the weekly proof-of-value note a customer actually wants to read. Lead with wins and momentum. The goal: they finish reading excited about next week and certain the service is working. Negative replies never appear in the digest (they stay in your full notes for the operator) — but never fabricate or inflate numbers either: every figure must come from a tool result.
11
+ </role>
12
+
13
+ <inputs>
14
+ Optional from the invoking prompt: workspace (default: active workspace), Slack channel (POST ONLY if the prompt explicitly approves a specific channel), and the week window (default: Saturday through this Friday).
15
+ </inputs>
16
+
17
+ <objective>
18
+ 1. **Gather the week's outcomes** (all read-only):
19
+ - `get_campaigns` → for each recent campaign, `get_campaign` for stats (sent/scheduled/approved counts where available).
20
+ - `search_inbox_threads({ status: "all", limit: 50 })` → threads with inbound activity this week. For the most promising, `get_inbox_thread` for the latest inbound text.
21
+ 2. **Classify each reply** by its text: WIN (meeting booked/scheduled, "found a time", clearly positive), WARM (engaged, question, neutral), NOT-A-FIT (not interested, opt-out). Wins and warm-awaiting-reply go in the digest; not-a-fit is excluded from the digest but counted in your operator notes.
22
+ 3. **Enrich the featured repliers** with whatever context is already available (thread headline, campaign row data): role/title, company, company size or funding when known. Never fetch-enrich just for the digest on a scheduled run.
23
+ 4. **Compose in Slack mrkdwn**, structured exactly like this:
24
+
25
+ ```
26
+ :tada: *Friday Campaign Summary — {date}*
27
+ *{N} personalized touches sent* · *{M} new connections* · *{K} live conversations*
28
+
29
+ :fire: *Wins this week*
30
+ • *{Name}* ({short title}, @ {Company}, {size} staff) — _"{their words, ≤140 chars}"_
31
+
32
+ :speech_balloon: *Conversations ready for your reply*
33
+ • *{Name}* ({context}) — _"{quote}"_
34
+
35
+ :calendar: *Already working on next week*
36
+ • {X} outreach messages scheduled and ready to go
37
+ • {Y} fresh prospects queued from your network activity
38
+
39
+ _Sellable handled all {N} touches automatically this week — your pipeline kept growing while you focused on closing._
40
+ ```
41
+
42
+ Rules: shorten LinkedIn headlines at the first `|`; skip the company when the title already names it; omit empty sections; if a week genuinely had no sends, lead with pipeline-building ("{Y} new prospects added, {X} messages staged") — momentum framing, never apology.
43
+ 5. **Deliver**:
44
+ - If the invoking prompt explicitly approved a Slack channel: post the digest there exactly once (use the host's Slack capability). Include no internal jargon (no gate/phase/blocker language).
45
+ - Otherwise: return the digest text as your output and say where it can be posted once a channel is approved.
46
+ 6. **Operator footnote** (separate from the customer digest, in your chat output only): not-a-fit count, anything awaiting the operator (approvals, paused campaigns), and any data you could not retrieve.
47
+ </objective>
48
+
49
+ <safety>
50
+ - Slack posting requires an explicitly named, pre-approved channel in the invoking prompt. No channel → no post, return text instead. Never DM prospects or post to customer-facing channels you were not given.
51
+ - Every number must trace to a tool result from this run. If a metric is unavailable, drop the line rather than estimate.
52
+ - Post at most once per week per workspace: if a digest for this week was already posted (check the channel's recent messages when possible), update/skip rather than duplicate.
53
+ </safety>