@sellable/mcp 0.1.416 → 0.1.417
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/README.md +2 -5
- package/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/tools/refill-sends.d.ts +2 -21
- package/dist/tools/refill-sends.js +2 -47
- package/package.json +1 -1
- package/skills/create-campaign-v2/references/ai-tells.md +6 -0
- package/skills/create-campaign-v2/references/gold-standard-message-examples.md +34 -7
- package/skills/create-campaign-v2/references/gold-standard-message-patterns.md +11 -1
- package/skills/create-campaign-v2/references/sellable-cleanup-rules.md +1 -1
- package/skills/create-evergreen-campaigns/SKILL.md +470 -34
- package/skills/generate-messages/SKILL.md +94 -33
- package/skills/refill-sends/SKILL.md +8 -15
package/README.md
CHANGED
|
@@ -66,9 +66,8 @@ reader value, validates proof/AI tells, and saves content artifacts under
|
|
|
66
66
|
|
|
67
67
|
The refill-sends public command wrapper plans and executes approval-gated send
|
|
68
68
|
refills. It supports `--yolo` and optional sender selectors such as
|
|
69
|
-
`--sender "Christian Reyes"
|
|
70
|
-
|
|
71
|
-
untilDate })` from:
|
|
69
|
+
`--sender "Christian Reyes"` or typed MCP calls to `refill_sends({ yolo,
|
|
70
|
+
senders })` from:
|
|
72
71
|
|
|
73
72
|
- `mcp/sellable/skills/refill-sends/SKILL.md`
|
|
74
73
|
|
|
@@ -297,7 +296,6 @@ Use the refill command for sender send refills:
|
|
|
297
296
|
|
|
298
297
|
```
|
|
299
298
|
/sellable:refill-sends --yolo
|
|
300
|
-
/sellable:refill-sends --yolo --until 2026-06-30
|
|
301
299
|
/sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"
|
|
302
300
|
```
|
|
303
301
|
|
|
@@ -325,7 +323,6 @@ Use the Codex refill command with the same flags:
|
|
|
325
323
|
|
|
326
324
|
```
|
|
327
325
|
$sellable:refill-sends --yolo
|
|
328
|
-
$sellable:refill-sends --yolo --until 2026-06-30
|
|
329
326
|
$sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"
|
|
330
327
|
```
|
|
331
328
|
|
package/dist/index-dev.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
File without changes
|
|
@@ -6,7 +6,6 @@ type RefillSendsCommandInput = {
|
|
|
6
6
|
senderIds?: string[];
|
|
7
7
|
senderNames?: string[];
|
|
8
8
|
horizonSendDays?: number;
|
|
9
|
-
untilDate?: string;
|
|
10
9
|
campaignId?: string;
|
|
11
10
|
tableId?: string;
|
|
12
11
|
intent?: RefillSendsIntent;
|
|
@@ -49,11 +48,6 @@ export declare const refillSendsToolDefinitions: {
|
|
|
49
48
|
maximum: number;
|
|
50
49
|
description: string;
|
|
51
50
|
};
|
|
52
|
-
untilDate: {
|
|
53
|
-
type: string;
|
|
54
|
-
pattern: string;
|
|
55
|
-
description: string;
|
|
56
|
-
};
|
|
57
51
|
campaignId: {
|
|
58
52
|
type: string;
|
|
59
53
|
description: string;
|
|
@@ -84,19 +78,7 @@ export declare function refillSendsCommand(input?: RefillSendsCommandInput): {
|
|
|
84
78
|
workflowPromptName: string;
|
|
85
79
|
yolo: boolean;
|
|
86
80
|
intent: RefillSendsIntent;
|
|
87
|
-
|
|
88
|
-
horizonSendDays: number | null;
|
|
89
|
-
fillWindow: {
|
|
90
|
-
mode: string;
|
|
91
|
-
untilDate: string;
|
|
92
|
-
description: string;
|
|
93
|
-
horizonSendDays?: undefined;
|
|
94
|
-
} | {
|
|
95
|
-
mode: string;
|
|
96
|
-
horizonSendDays: number | null;
|
|
97
|
-
description: string;
|
|
98
|
-
untilDate?: undefined;
|
|
99
|
-
};
|
|
81
|
+
horizonSendDays: number;
|
|
100
82
|
approvalMode: RefillSendsApprovalMode;
|
|
101
83
|
campaignId: string | null;
|
|
102
84
|
tableId: string | null;
|
|
@@ -119,8 +101,7 @@ export declare function refillSendsCommand(input?: RefillSendsCommandInput): {
|
|
|
119
101
|
senders: string[];
|
|
120
102
|
senderIds: string[];
|
|
121
103
|
senderNames: string[];
|
|
122
|
-
|
|
123
|
-
horizonSendDays: number | null;
|
|
104
|
+
horizonSendDays: number;
|
|
124
105
|
campaignId: string | undefined;
|
|
125
106
|
tableId: string | undefined;
|
|
126
107
|
intent: RefillSendsIntent;
|
|
@@ -14,25 +14,6 @@ function normalizeHorizonSendDays(value) {
|
|
|
14
14
|
}
|
|
15
15
|
return Math.max(1, Math.min(7, Math.floor(value)));
|
|
16
16
|
}
|
|
17
|
-
function normalizeUntilDate(value) {
|
|
18
|
-
if (value === undefined || value === null || value === "")
|
|
19
|
-
return null;
|
|
20
|
-
if (typeof value !== "string") {
|
|
21
|
-
throw new Error("untilDate must be a string in YYYY-MM-DD format.");
|
|
22
|
-
}
|
|
23
|
-
const trimmed = value.trim();
|
|
24
|
-
if (!/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
|
|
25
|
-
throw new Error("untilDate must use YYYY-MM-DD format.");
|
|
26
|
-
}
|
|
27
|
-
const [year, month, day] = trimmed.split("-").map((part) => Number(part));
|
|
28
|
-
const parsed = new Date(Date.UTC(year, month - 1, day));
|
|
29
|
-
if (parsed.getUTCFullYear() !== year ||
|
|
30
|
-
parsed.getUTCMonth() !== month - 1 ||
|
|
31
|
-
parsed.getUTCDate() !== day) {
|
|
32
|
-
throw new Error("untilDate must be a valid calendar date.");
|
|
33
|
-
}
|
|
34
|
-
return trimmed;
|
|
35
|
-
}
|
|
36
17
|
export const refillSendsToolDefinitions = [
|
|
37
18
|
{
|
|
38
19
|
name: "refill_sends",
|
|
@@ -63,12 +44,7 @@ export const refillSendsToolDefinitions = [
|
|
|
63
44
|
type: "number",
|
|
64
45
|
minimum: 1,
|
|
65
46
|
maximum: 7,
|
|
66
|
-
description: "Number of sender-local send days to fill. Defaults to 2
|
|
67
|
-
},
|
|
68
|
-
untilDate: {
|
|
69
|
-
type: "string",
|
|
70
|
-
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
|
|
71
|
-
description: "Optional sender-local YYYY-MM-DD date to fill through, inclusive. Overrides the default two send-day horizon.",
|
|
47
|
+
description: "Number of sender-local send days to fill. Defaults to 2.",
|
|
72
48
|
},
|
|
73
49
|
campaignId: {
|
|
74
50
|
type: "string",
|
|
@@ -100,10 +76,7 @@ export function refillSendsCommand(input = {}) {
|
|
|
100
76
|
const senderNames = normalizeStrings(input.senderNames);
|
|
101
77
|
const hasSenderSelectors = senders.length > 0 || senderIds.length > 0 || senderNames.length > 0;
|
|
102
78
|
const yolo = input.yolo === true;
|
|
103
|
-
const
|
|
104
|
-
const horizonSendDays = untilDate
|
|
105
|
-
? null
|
|
106
|
-
: normalizeHorizonSendDays(input.horizonSendDays);
|
|
79
|
+
const horizonSendDays = normalizeHorizonSendDays(input.horizonSendDays);
|
|
107
80
|
const intent = input.intent ?? "plain";
|
|
108
81
|
const approvalMode = input.approvalMode ?? (yolo ? "approve" : "mark_ready");
|
|
109
82
|
const senderScope = hasSenderSelectors
|
|
@@ -118,19 +91,7 @@ export function refillSendsCommand(input = {}) {
|
|
|
118
91
|
workflowPromptName: "refill-sends-workflow",
|
|
119
92
|
yolo,
|
|
120
93
|
intent,
|
|
121
|
-
untilDate,
|
|
122
94
|
horizonSendDays,
|
|
123
|
-
fillWindow: untilDate
|
|
124
|
-
? {
|
|
125
|
-
mode: "until_date",
|
|
126
|
-
untilDate,
|
|
127
|
-
description: "Fill through this sender-local date inclusive, skipping no-send days and never extending beyond the date without a new packet.",
|
|
128
|
-
}
|
|
129
|
-
: {
|
|
130
|
-
mode: "horizon_send_days",
|
|
131
|
-
horizonSendDays,
|
|
132
|
-
description: "Fill the default bounded horizon by sender-local send days.",
|
|
133
|
-
},
|
|
134
95
|
approvalMode,
|
|
135
96
|
campaignId: input.campaignId ?? null,
|
|
136
97
|
tableId: input.tableId ?? null,
|
|
@@ -144,9 +105,6 @@ export function refillSendsCommand(input = {}) {
|
|
|
144
105
|
'Load get_subskill_prompt({ subskillName: "refill-sends-workflow" }) before any product operation.',
|
|
145
106
|
`Resolve route with resolve_campaign_fill_route({ intent: "${intent}"${input.campaignId ? `, campaignId: "${input.campaignId}"` : ""}${input.tableId ? `, tableId: "${input.tableId}"` : ""} }).`,
|
|
146
107
|
"Call list_senders and get_sender_routing, then resolve sender selectors against active enrolled campaign-backed sequence senders.",
|
|
147
|
-
untilDate
|
|
148
|
-
? `Use fill window untilDate="${untilDate}" as the inclusive sender-local through date; do not extend beyond that date without a new approval packet.`
|
|
149
|
-
: `Use the default fill window of ${horizonSendDays} sender-local send days.`,
|
|
150
108
|
"Read get_campaign_refill_state for enough exact candidate campaigns to pick the best per-sender target by recent/future scheduler-owned sends, then recent result evidence, then source health.",
|
|
151
109
|
"Fresh reread get_campaign_refill_state immediately before any import, prep, approval, or horizon-fill mutation.",
|
|
152
110
|
],
|
|
@@ -167,12 +125,10 @@ export function refillSendsCommand(input = {}) {
|
|
|
167
125
|
hostExamples: {
|
|
168
126
|
claude: [
|
|
169
127
|
"/sellable:refill-sends --yolo",
|
|
170
|
-
"/sellable:refill-sends --yolo --until 2026-06-30",
|
|
171
128
|
'/sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"',
|
|
172
129
|
],
|
|
173
130
|
codex: [
|
|
174
131
|
"$sellable:refill-sends --yolo",
|
|
175
|
-
"$sellable:refill-sends --yolo --until 2026-06-30",
|
|
176
132
|
'$sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"',
|
|
177
133
|
],
|
|
178
134
|
mcpTool: {
|
|
@@ -182,7 +138,6 @@ export function refillSendsCommand(input = {}) {
|
|
|
182
138
|
senders,
|
|
183
139
|
senderIds,
|
|
184
140
|
senderNames,
|
|
185
|
-
untilDate,
|
|
186
141
|
horizonSendDays,
|
|
187
142
|
campaignId: input.campaignId,
|
|
188
143
|
tableId: input.tableId,
|
package/package.json
CHANGED
|
@@ -55,6 +55,12 @@ raise your hand for X (creepy to reach out based on that, i know) - but
|
|
|
55
55
|
this felt too on the nose to ignore"` shapes only when the source was an
|
|
56
56
|
explicit lead-magnet comment, reply, or opt-in.
|
|
57
57
|
|
|
58
|
+
Shared evergreen exception: for Shared Signal Discovery and other shared
|
|
59
|
+
evergreen lanes, the weak-signal permissioned bridge above is still a tell.
|
|
60
|
+
Reject `hope this is relevant`, `might be interested`, and `saw you in a few
|
|
61
|
+
conversations` as openers; require a concrete signal/problem bridge or omit the
|
|
62
|
+
source line.
|
|
63
|
+
|
|
58
64
|
**Severity:** REJECT
|
|
59
65
|
|
|
60
66
|
## Tell #3 — Explicit date or duration references about the recipient
|
|
@@ -203,6 +203,32 @@ Why it works:
|
|
|
203
203
|
**Proof ranks used:** rank 1 (mechanism - 1,000+ conditions from one blood
|
|
204
204
|
draw), rank 3 (risk before claims).
|
|
205
205
|
|
|
206
|
+
Do not use the Superpower weak-signal hedge pattern for Shared Evergreen Signal Discovery. Shared evergreen lanes are reused across multiple senders and must not open with `hope this is relevant`, `might be interested`, or `saw you in a few conversations`. Use the safe pattern below instead.
|
|
207
|
+
|
|
208
|
+
### Shared Evergreen Signal Discovery Safe Pattern
|
|
209
|
+
|
|
210
|
+
Use when the campaign is a shared evergreen signal lane and the source signal is
|
|
211
|
+
real but not sender-owned.
|
|
212
|
+
|
|
213
|
+
```text
|
|
214
|
+
Hey {{first_name}},
|
|
215
|
+
|
|
216
|
+
The AI-assisted GTM conversations keep coming back to one problem: turning good LinkedIn signal into review-ready pipeline without another outbound dashboard.
|
|
217
|
+
|
|
218
|
+
Sellable helps teams find signal-matched prospects, filter for fit, and generate reviewed LinkedIn copy from one workflow.
|
|
219
|
+
|
|
220
|
+
Curious if LinkedIn outbound is a channel you're trying to make more reliable this quarter?
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Why it works:
|
|
224
|
+
|
|
225
|
+
- no low-confidence relevance hedge
|
|
226
|
+
- no `I'm building` or founder-only first person
|
|
227
|
+
- no internal workflow vocabulary such as Codex, MCP, agent workflows, workflow
|
|
228
|
+
table, lead source, or signal discovery
|
|
229
|
+
- the signal becomes a buyer problem instead of an activity-log opener
|
|
230
|
+
- safe for multiple senders attached to the same shared lane
|
|
231
|
+
|
|
206
232
|
## Conditional Examples
|
|
207
233
|
|
|
208
234
|
Use these only when the campaign motion matches.
|
|
@@ -419,24 +445,25 @@ Tokenized shape:
|
|
|
419
445
|
Hey there
|
|
420
446
|
|
|
421
447
|
Thanks for the support on my post about {{post_topic_line}}
|
|
422
|
-
|
|
423
|
-
Curious, is this something you're dealing with right now?
|
|
424
448
|
```
|
|
425
449
|
|
|
426
450
|
Transfer rules:
|
|
427
451
|
|
|
428
452
|
- Do not hardcode a post topic. Fill `{{post_topic_line}}` from the actual
|
|
429
453
|
selected sender-authored post or use a safer source-specific phrase.
|
|
454
|
+
- Do not add a relevance question, CTA, product line, or extra paragraph after
|
|
455
|
+
the thank-you line. The reply-rate lesson is the casual warm acknowledgment,
|
|
456
|
+
not a cold pitch appended to it.
|
|
430
457
|
- Do not use "showing some love"; it reads too casual for executive/VP/director
|
|
431
458
|
contacts.
|
|
432
459
|
- Keep the thank-you line. The point of this motion is acknowledging real
|
|
433
|
-
sender-owned support
|
|
434
|
-
it back to "saw you pop up" unless the sender specifically asks for
|
|
435
|
-
wording.
|
|
460
|
+
sender-owned support without appending a cold relevance question. Do not
|
|
461
|
+
flatten it back to "saw you pop up" unless the sender specifically asks for
|
|
462
|
+
that wording.
|
|
436
463
|
- Do not copy this shape into shared lanes, third-party thread sources, or cold
|
|
437
464
|
fallback campaigns.
|
|
438
|
-
-
|
|
439
|
-
|
|
465
|
+
- Do not pitch, ask for a meeting, or mention internal product vocabulary in
|
|
466
|
+
message one.
|
|
440
467
|
|
|
441
468
|
## Useful CTA Shapes
|
|
442
469
|
|
|
@@ -199,11 +199,21 @@ Shape:
|
|
|
199
199
|
Prefer:
|
|
200
200
|
|
|
201
201
|
- lowercase or casual casing when the motion supports it
|
|
202
|
-
- an honest line like "hope this is relevant" or "so may be off, but this seemed relevant"
|
|
202
|
+
- an honest line like "hope this is relevant" or "so may be off, but this seemed relevant" only for non-evergreen weak-signal campaigns
|
|
203
203
|
- a concrete CTA that names the useful conversation or asset
|
|
204
204
|
- binary options only when the brief explicitly supports two real next steps
|
|
205
205
|
- direct wording over polished marketing language
|
|
206
206
|
|
|
207
|
+
Shared Evergreen Signal Discovery override:
|
|
208
|
+
|
|
209
|
+
- Do not use `hope this is relevant`, `might be interested`, or `saw you in a
|
|
210
|
+
few conversations` as the opener.
|
|
211
|
+
- Do not use `I'm building`, `I've mapped`, `my company`, or `my team`.
|
|
212
|
+
- Turn the source topic into a buyer problem bridge, then write the product line
|
|
213
|
+
in team/company voice.
|
|
214
|
+
- If the source topic cannot support a concrete bridge, omit the source line and
|
|
215
|
+
start from a role/company/problem observation.
|
|
216
|
+
|
|
207
217
|
Avoid:
|
|
208
218
|
|
|
209
219
|
- copying a gimmick like "from a claude code terminal" unless the brief
|
|
@@ -74,7 +74,7 @@ Revise or reject the sample when any of these happen.
|
|
|
74
74
|
- **actions are implied, not stated** — e.g. "runs that chain as AI agents" when a clearer version would name the specific actions (verb + object, one per line)
|
|
75
75
|
- **category-level opener used when a per-lead signal exists** — if `lead-sample.json` carries any per-lead signal (post, hire, visible tool, topic engagement), the opener must reference it. Category-level openers of shape `"Most [category] teams still do X by hand"` are only acceptable when zero per-lead signal is in the sample. When a category-level opener is used as fallback, Findings must flag it explicitly
|
|
76
76
|
- **mind-reading from engagement signals** — a topic engagement, post, public activity, role, company, or hiring trigger does not prove buyer intent. Reject phrases like `"AI-GTM stack is clearly on your mind"`, `"you're clearly focused on..."`, `"obviously relevant"`, or `"already thinking about..."` unless that exact priority is explicitly present in `lead-sample.json`. Translate to low-certainty buyer context or omit the signal from copy.
|
|
77
|
-
- **source-y signal narration** — reject `"saw you on..."`, `"saw you engaging with..."`, `"you commented on..."`, `"your LinkedIn activity..."`, `"you might not remember the thread..."`, `"found you through [source] and your role looked close..."`, or any line that makes the recipient feel watched unless the chosen archived motion is intentionally self-aware about the signal. For sender-owned LinkedIn post sources, a light first-person acknowledgment is allowed when row data proves a reaction/comment: `"appreciate you showing some love on my post about [topic]"` or `"thanks for showing support on my [topic] post"`. Do not name a comment unless comment text is present. Follow the acknowledgment with a soft relevance bridge before broad pain/product copy, e.g. `"figured this might be relevant if LinkedIn is becoming more of a GTM channel for [company]"`. For third-party LinkedIn-post-sourced campaigns, a topic-level bridge is allowed when it explains why the note exists and stays apologetically uncertain: `"saw you in a few conversations about [topic], so may be off, but this seemed relevant."`, `"saw you in a few conversations around [topic], so hope this is relevant."`, or `"found you in a thread about [topic], so may be off, but this seemed relevant."` Reserve `"raise your hand"` language for explicit lead-magnet comments, replies, or opt-ins. Translate the signal into natural buyer context or omit it.
|
|
77
|
+
- **source-y signal narration** — reject `"saw you on..."`, `"saw you engaging with..."`, `"you commented on..."`, `"your LinkedIn activity..."`, `"you might not remember the thread..."`, `"found you through [source] and your role looked close..."`, or any line that makes the recipient feel watched unless the chosen archived motion is intentionally self-aware about the signal. For sender-owned LinkedIn post sources, a light first-person acknowledgment is allowed when row data proves a reaction/comment: `"appreciate you showing some love on my post about [topic]"` or `"thanks for showing support on my [topic] post"`. Do not name a comment unless comment text is present. Follow the acknowledgment with a soft relevance bridge before broad pain/product copy, e.g. `"figured this might be relevant if LinkedIn is becoming more of a GTM channel for [company]"`. For third-party LinkedIn-post-sourced campaigns, a topic-level bridge is allowed when it explains why the note exists and stays apologetically uncertain: `"saw you in a few conversations about [topic], so may be off, but this seemed relevant."`, `"saw you in a few conversations around [topic], so hope this is relevant."`, or `"found you in a thread about [topic], so may be off, but this seemed relevant."` Shared evergreen signal exception: these hedges are blocked for Shared Signal Discovery and other shared evergreen lanes; use a concrete signal/problem bridge or omit the source line. Reserve `"raise your hand"` language for explicit lead-magnet comments, replies, or opt-ins. Translate the signal into natural buyer context or omit it.
|
|
78
78
|
- **sender-owned source rendered as third-party** — hard fail when the source post is sender-owned and the draft says `"found you in a thread"`, `"saw you in a thread"`, `"saw you in conversations"`, or `"saw you in a few conversations"` as if the post were third-party. For sender-owned sources, the copy must either use a light first-person acknowledgment plus a soft relevance bridge, or omit the source line. If multiple senders may send the campaign, or the final sender/source-owner match is ambiguous, do not assume a specific `my post` voice or name a specific sender; omit the sender-owned source line until row-level sender ownership is proven. Neutral low-certainty thread/source language is only for truly third-party sources.
|
|
79
79
|
- **fake line-to-line continuity** — reject line stacks where the source acknowledgment, relevance bridge, product line, and CTA do not actually build on each other. Each line must make the next line feel earned. If two adjacent lines could be swapped, deleted, or joined with `"anyway"` without changing the meaning, the transition is fake. In sender-owned post campaigns, the chain should be: support on my post -> why this topic may matter for the company -> what the product/problem does about that same topic -> low-friction next step.
|
|
80
80
|
- **assumptive title-fit opener** — reject `"Your [role] role at [company] looked close to this problem"` or `"looked close to this outbound campaign problem"`. This asserts fit from title/company. Keep the apologetic uncertainty instead: `"may be off, but if [workflow] is relevant to what you're working on..."`.
|