@sellable/mcp 0.1.408 → 0.1.410

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 CHANGED
@@ -16,7 +16,7 @@ Each message gets 5+ minutes of Claude attention with deep research - no other t
16
16
 
17
17
  ### Prompt Source Of Truth
18
18
 
19
- There are six public Sellable entrypoints shared across hosts:
19
+ There are seven public Sellable entrypoints shared across hosts:
20
20
 
21
21
  - `sellable:create-campaign`
22
22
  - `sellable:create-ab-test`
@@ -24,6 +24,7 @@ There are six public Sellable entrypoints shared across hosts:
24
24
  - `sellable:foundation`
25
25
  - `sellable:content`
26
26
  - `sellable:create-post`
27
+ - `sellable:refill-sends`
27
28
 
28
29
  The create-campaign public wrapper at
29
30
  `mcp/sellable/skills/create-campaign/SKILL.md` handles auth/bootstrap and loads
@@ -63,6 +64,13 @@ reader value, validates proof/AI tells, and saves content artifacts under
63
64
 
64
65
  - `mcp/sellable/skills/create-post/SKILL.md`
65
66
 
67
+ The refill-sends public command wrapper plans and executes approval-gated send
68
+ refills. It supports `--yolo` and optional sender selectors such as
69
+ `--sender "Christian Reyes"` or typed MCP calls to `refill_sends({ yolo,
70
+ senders })` from:
71
+
72
+ - `mcp/sellable/skills/refill-sends/SKILL.md`
73
+
66
74
  Keep `create-campaign-v2` and `load-voice` internal. Do not advertise either as
67
75
  a public command. `load-voice` remains a direct MCP utility for generic writing
68
76
  surfaces that are not posts or campaigns.
@@ -186,10 +194,10 @@ The installer does the full local setup:
186
194
  After the installer passes, fully quit and reopen Codex Desktop. Start a new
187
195
  thread and select `Sellable Create Campaign`, `Sellable Create A/B Test`,
188
196
  `Sellable Create Evergreen Campaigns`, `Sellable Foundation`,
189
- `Sellable Content`, or `Sellable Create Post`; or invoke
197
+ `Sellable Content`, `Sellable Create Post`, or `Sellable Refill Sends`; or invoke
190
198
  `$sellable:create-campaign`, `$sellable:create-ab-test`,
191
199
  `$sellable:create-evergreen-campaigns`, `$sellable:foundation`,
192
- `$sellable:content`, or `$sellable:create-post`. If the app still says
200
+ `$sellable:content`, `$sellable:create-post`, or `$sellable:refill-sends`. If the app still says
193
201
  `mcp__sellable__*` tools are missing after the installer passes, check that
194
202
  `~/.codex/config.toml` contains both `[marketplaces.sellable]` and
195
203
  `[plugins."sellable@sellable"]`.
@@ -206,12 +214,14 @@ Use these names consistently:
206
214
  - Claude Code command: `/sellable:foundation`
207
215
  - Claude Code command: `/sellable:content`
208
216
  - Claude Code command: `/sellable:create-post`
217
+ - Claude Code command: `/sellable:refill-sends`
209
218
  - Codex command: `$sellable:create-campaign`
210
219
  - Codex command: `$sellable:create-ab-test`
211
220
  - Codex command: `$sellable:create-evergreen-campaigns`
212
221
  - Codex command: `$sellable:foundation`
213
222
  - Codex command: `$sellable:content`
214
223
  - Codex command: `$sellable:create-post`
224
+ - Codex command: `$sellable:refill-sends`
215
225
  - Codex Desktop plugin: `sellable@sellable`
216
226
  - Codex visible skill: `Sellable Create Campaign`
217
227
  - Codex visible skill: `Sellable Create A/B Test`
@@ -219,14 +229,17 @@ Use these names consistently:
219
229
  - Codex visible skill: `Sellable Foundation`
220
230
  - Codex visible skill: `Sellable Content`
221
231
  - Codex visible skill: `Sellable Create Post`
232
+ - Codex visible skill: `Sellable Refill Sends`
222
233
  - Codex skill frontmatter name: `create-campaign`
223
234
  - Codex skill frontmatter name: `create-ab-test`
224
235
  - Codex skill frontmatter name: `create-evergreen-campaigns`
225
236
  - Codex skill frontmatter name: `foundation`
226
237
  - Codex skill frontmatter name: `content`
227
238
  - Codex skill frontmatter name: `create-post`
239
+ - Codex skill frontmatter name: `refill-sends`
228
240
  - MCP server name: `sellable`
229
241
  - Internal workflow prompt: `create-campaign-v2`
242
+ - Internal workflow prompt: `refill-sends-workflow`
230
243
  - Internal/backward-compatible memory prompt: `interview`
231
244
 
232
245
  Never tell users to run `/sellable:create-campaign-v2`,
@@ -279,6 +292,13 @@ Use the create-campaign skill:
279
292
  /sellable:create-campaign
280
293
  ```
281
294
 
295
+ Use the refill command for sender send refills:
296
+
297
+ ```
298
+ /sellable:refill-sends --yolo
299
+ /sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"
300
+ ```
301
+
282
302
  Then describe intent naturally, for example:
283
303
 
284
304
  - "Let's make a campaign with sellable"
@@ -299,6 +319,13 @@ Use the Codex skill entrypoint:
299
319
  $sellable:create-campaign
300
320
  ```
301
321
 
322
+ Use the Codex refill command with the same flags:
323
+
324
+ ```
325
+ $sellable:refill-sends --yolo
326
+ $sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"
327
+ ```
328
+
302
329
  Installed skill package path:
303
330
 
304
331
  - `~/.codex/plugins/cache/sellable/sellable/<version>/skills/sellable-create-campaign/SKILL.md`
package/dist/server.js CHANGED
@@ -37,6 +37,7 @@ import { addOnDemandLeads, createOnDemandCampaign, createOnDemandTable, initOnDe
37
37
  import { upsertRubric } from "./tools/processing.js";
38
38
  import { completeSenderResearch, getPostFindLeadsScoutRegistry, getSourceScoutRegistry, getSubskillAsset, getSubskillPrompt, listSubskillPrompts, searchSubskillPrompts, } from "./tools/prompts.js";
39
39
  import { waitForCampaignTableReady, waitForLeadListReady, } from "./tools/readiness.js";
40
+ import { refillSendsCommand } from "./tools/refill-sends.js";
40
41
  import { allTools } from "./tools/registry.js";
41
42
  import { getRows, getTableRows, getTableRowsMinimal } from "./tools/rows.js";
42
43
  import { addRubricItem, checkRubric, deleteRubricItem, draftRubrics, saveRubrics, selectNecessaryRubrics, updateRubricItem, waitForRubricResults, } from "./tools/rubrics.js";
@@ -217,6 +218,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
217
218
  case "get_campaign_refill_state":
218
219
  result = await getCampaignRefillState(args);
219
220
  break;
221
+ case "refill_sends":
222
+ result = refillSendsCommand(args);
223
+ break;
220
224
  case "setup_evergreen_campaigns":
221
225
  result = await setupEvergreenCampaigns(args);
222
226
  markEvergreenSetupCampaignsDirty(args);
@@ -0,0 +1,113 @@
1
+ type RefillSendsIntent = "plain" | "active" | "evergreen";
2
+ type RefillSendsApprovalMode = "approve" | "mark_ready";
3
+ type RefillSendsCommandInput = {
4
+ yolo?: boolean;
5
+ senders?: string[];
6
+ senderIds?: string[];
7
+ senderNames?: string[];
8
+ horizonSendDays?: number;
9
+ campaignId?: string;
10
+ tableId?: string;
11
+ intent?: RefillSendsIntent;
12
+ approvalMode?: RefillSendsApprovalMode;
13
+ };
14
+ export declare const refillSendsToolDefinitions: {
15
+ name: string;
16
+ description: string;
17
+ inputSchema: {
18
+ type: string;
19
+ properties: {
20
+ yolo: {
21
+ type: string;
22
+ description: string;
23
+ };
24
+ senders: {
25
+ type: string;
26
+ items: {
27
+ type: string;
28
+ };
29
+ description: string;
30
+ };
31
+ senderIds: {
32
+ type: string;
33
+ items: {
34
+ type: string;
35
+ };
36
+ description: string;
37
+ };
38
+ senderNames: {
39
+ type: string;
40
+ items: {
41
+ type: string;
42
+ };
43
+ description: string;
44
+ };
45
+ horizonSendDays: {
46
+ type: string;
47
+ minimum: number;
48
+ maximum: number;
49
+ description: string;
50
+ };
51
+ campaignId: {
52
+ type: string;
53
+ description: string;
54
+ };
55
+ tableId: {
56
+ type: string;
57
+ description: string;
58
+ };
59
+ intent: {
60
+ type: string;
61
+ enum: string[];
62
+ description: string;
63
+ };
64
+ approvalMode: {
65
+ type: string;
66
+ enum: string[];
67
+ description: string;
68
+ };
69
+ };
70
+ required: never[];
71
+ additionalProperties: boolean;
72
+ };
73
+ }[];
74
+ export declare function refillSendsCommand(input?: RefillSendsCommandInput): {
75
+ command: string;
76
+ tool: string;
77
+ promptName: string;
78
+ workflowPromptName: string;
79
+ yolo: boolean;
80
+ intent: RefillSendsIntent;
81
+ horizonSendDays: number;
82
+ approvalMode: RefillSendsApprovalMode;
83
+ campaignId: string | null;
84
+ tableId: string | null;
85
+ senderScope: string;
86
+ senderSelectors: {
87
+ senders: string[];
88
+ senderIds: string[];
89
+ senderNames: string[];
90
+ };
91
+ firstOperationalSteps: string[];
92
+ approvalContract: string;
93
+ forbiddenActions: string[];
94
+ hostExamples: {
95
+ claude: string[];
96
+ codex: string[];
97
+ mcpTool: {
98
+ name: string;
99
+ arguments: {
100
+ yolo: boolean;
101
+ senders: string[];
102
+ senderIds: string[];
103
+ senderNames: string[];
104
+ horizonSendDays: number;
105
+ campaignId: string | undefined;
106
+ tableId: string | undefined;
107
+ intent: RefillSendsIntent;
108
+ approvalMode: RefillSendsApprovalMode;
109
+ };
110
+ };
111
+ };
112
+ };
113
+ export {};
@@ -0,0 +1,150 @@
1
+ const DEFAULT_HORIZON_SEND_DAYS = 2;
2
+ function normalizeStrings(values) {
3
+ if (!Array.isArray(values))
4
+ return [];
5
+ return [
6
+ ...new Set(values
7
+ .map((value) => (typeof value === "string" ? value.trim() : ""))
8
+ .filter(Boolean)),
9
+ ];
10
+ }
11
+ function normalizeHorizonSendDays(value) {
12
+ if (typeof value !== "number" || !Number.isFinite(value)) {
13
+ return DEFAULT_HORIZON_SEND_DAYS;
14
+ }
15
+ return Math.max(1, Math.min(7, Math.floor(value)));
16
+ }
17
+ export const refillSendsToolDefinitions = [
18
+ {
19
+ name: "refill_sends",
20
+ description: "Typed command entrypoint for Sellable refill sends. Accepts --yolo semantics and optional sender selectors, then returns the bounded execution contract for the skill-led refill workflow. This tool does not mutate campaigns, import leads, approve messages, schedule sends, launch, archive, delete, or write scheduler rows.",
21
+ inputSchema: {
22
+ type: "object",
23
+ properties: {
24
+ yolo: {
25
+ type: "boolean",
26
+ description: "When true, auto-accept the rendered bounded refill packet after the required fresh state reread. Without sender selectors, yolo means all eligible healthy senders enrolled in active campaign-backed sequence campaigns.",
27
+ },
28
+ senders: {
29
+ type: "array",
30
+ items: { type: "string" },
31
+ description: "Optional sender selectors as names or ids. Use this for command text like --sender 'Christian Reyes'. Exact resolution still happens through list_senders before mutation.",
32
+ },
33
+ senderIds: {
34
+ type: "array",
35
+ items: { type: "string" },
36
+ description: "Optional exact Sender.id values to scope refill work.",
37
+ },
38
+ senderNames: {
39
+ type: "array",
40
+ items: { type: "string" },
41
+ description: "Optional sender display names to resolve through list_senders before campaign selection.",
42
+ },
43
+ horizonSendDays: {
44
+ type: "number",
45
+ minimum: 1,
46
+ maximum: 7,
47
+ description: "Number of sender-local send days to fill. Defaults to 2.",
48
+ },
49
+ campaignId: {
50
+ type: "string",
51
+ description: "Optional exact CampaignOffer.id to narrow routing. Do not pass campaign names.",
52
+ },
53
+ tableId: {
54
+ type: "string",
55
+ description: "Optional exact WorkflowTable.id to narrow routing. Do not pass table names.",
56
+ },
57
+ intent: {
58
+ type: "string",
59
+ enum: ["plain", "active", "evergreen"],
60
+ description: 'Route intent. Use "plain" for normal refill/load requests unless the user explicitly says active or evergreen.',
61
+ },
62
+ approvalMode: {
63
+ type: "string",
64
+ enum: ["approve", "mark_ready"],
65
+ description: 'Preparation mode for the final packet. Use "approve" only when the user asked to fill/schedule sender sends; otherwise default to "mark_ready".',
66
+ },
67
+ },
68
+ required: [],
69
+ additionalProperties: false,
70
+ },
71
+ },
72
+ ];
73
+ export function refillSendsCommand(input = {}) {
74
+ const senders = normalizeStrings(input.senders);
75
+ const senderIds = normalizeStrings(input.senderIds);
76
+ const senderNames = normalizeStrings(input.senderNames);
77
+ const hasSenderSelectors = senders.length > 0 || senderIds.length > 0 || senderNames.length > 0;
78
+ const yolo = input.yolo === true;
79
+ const horizonSendDays = normalizeHorizonSendDays(input.horizonSendDays);
80
+ const intent = input.intent ?? "plain";
81
+ const approvalMode = input.approvalMode ?? (yolo ? "approve" : "mark_ready");
82
+ const senderScope = hasSenderSelectors
83
+ ? "selected_senders"
84
+ : yolo
85
+ ? "all_eligible_healthy_senders_enrolled_in_active_campaign_backed_sequences"
86
+ : "ask_user_for_eligible_enrolled_senders_before_mutation";
87
+ return {
88
+ command: "refill-sends",
89
+ tool: "refill_sends",
90
+ promptName: "refill-sends",
91
+ workflowPromptName: "refill-sends-workflow",
92
+ yolo,
93
+ intent,
94
+ horizonSendDays,
95
+ approvalMode,
96
+ campaignId: input.campaignId ?? null,
97
+ tableId: input.tableId ?? null,
98
+ senderScope,
99
+ senderSelectors: {
100
+ senders,
101
+ senderIds,
102
+ senderNames,
103
+ },
104
+ firstOperationalSteps: [
105
+ 'Load get_subskill_prompt({ subskillName: "refill-sends-workflow" }) before any product operation.',
106
+ `Resolve route with resolve_campaign_fill_route({ intent: "${intent}"${input.campaignId ? `, campaignId: "${input.campaignId}"` : ""}${input.tableId ? `, tableId: "${input.tableId}"` : ""} }).`,
107
+ "Call list_senders and get_sender_routing, then resolve sender selectors against active enrolled campaign-backed sequence senders.",
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.",
109
+ "Fresh reread get_campaign_refill_state immediately before any import, prep, approval, or horizon-fill mutation.",
110
+ ],
111
+ approvalContract: yolo
112
+ ? "Auto-accept only the rendered bounded refill packet after fresh reread. Stop if sender set, route, ids, caps, dates, blockers, or side-effect class drift."
113
+ : hasSenderSelectors
114
+ ? "Ask the final Accept/Decline structured approval question before mutation, including workspace, sender scope, campaign table, exact ids, caps/dates, side effects, forbidden actions, and stop condition."
115
+ : "Ask which eligible enrolled senders to refill first, then ask the final Accept/Decline structured approval question before mutation.",
116
+ forbiddenActions: [
117
+ "start_campaign",
118
+ "launch or send",
119
+ "archive or delete cleanup",
120
+ "direct scheduler writes",
121
+ "sender reassignment",
122
+ "campaigns outside the rendered eligible sender packet",
123
+ "on-demand or unrelated active-campaign fallback unless the refill workflow proves the selected same-sender lane is blocked or exhausted",
124
+ ],
125
+ hostExamples: {
126
+ claude: [
127
+ "/sellable:refill-sends --yolo",
128
+ '/sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"',
129
+ ],
130
+ codex: [
131
+ "$sellable:refill-sends --yolo",
132
+ '$sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"',
133
+ ],
134
+ mcpTool: {
135
+ name: "refill_sends",
136
+ arguments: {
137
+ yolo,
138
+ senders,
139
+ senderIds,
140
+ senderNames,
141
+ horizonSendDays,
142
+ campaignId: input.campaignId,
143
+ tableId: input.tableId,
144
+ intent,
145
+ approvalMode,
146
+ },
147
+ },
148
+ },
149
+ };
150
+ }
@@ -33,6 +33,7 @@ import { onDemandToolDefinitions } from "./one-off.js";
33
33
  import { processingToolDefinitions } from "./processing.js";
34
34
  import { promptToolDefinitions } from "./prompts.js";
35
35
  import { readinessToolDefinitions } from "./readiness.js";
36
+ import { refillSendsToolDefinitions } from "./refill-sends.js";
36
37
  import { rowToolDefinitions } from "./rows.js";
37
38
  import { rubricToolDefinitions } from "./rubrics.js";
38
39
  import { senderRoutingToolDefinitions } from "./sender-routing.js";
@@ -49,6 +50,7 @@ export const allTools = [
49
50
  ...campaignAbTestToolDefinitions,
50
51
  ...campaignFillRoutingToolDefinitions,
51
52
  ...campaignRefillStateToolDefinitions,
53
+ ...refillSendsToolDefinitions,
52
54
  ...setupEvergreenCampaignsToolDefinitions,
53
55
  ...campaignHorizonFillToolDefinitions,
54
56
  ...campaignMessagePreparationToolDefinitions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.408",
3
+ "version": "0.1.410",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -3,6 +3,13 @@ name: refill-sends
3
3
  description: Plan regular campaign and evergreen campaign send refill work through the skill-led refill workflow.
4
4
  visibility: public
5
5
  allowed-tools:
6
+ - mcp__sellable__refill_sends
7
+ - mcp__sellable__get_auth_status
8
+ - mcp__sellable__start_cli_login
9
+ - mcp__sellable__wait_for_cli_login
10
+ - mcp__sellable__get_active_workspace
11
+ - mcp__sellable__list_workspaces
12
+ - mcp__sellable__set_active_workspace
6
13
  - mcp__sellable__get_subskill_prompt
7
14
  - mcp__sellable__search_subskill_prompts
8
15
  - mcp__sellable__list_senders
@@ -45,8 +52,38 @@ allowed-tools:
45
52
 
46
53
  # Refill Sends
47
54
 
48
- Use this public wrapper for plain operator requests such as "fill", "refill sends",
49
- "max out sends", "load everyone up", or "fill horizon sends".
55
+ Use this public command wrapper for plain operator requests such as "fill",
56
+ "refill sends", "max out sends", "load everyone up", or "fill horizon sends".
57
+
58
+ Host command names:
59
+
60
+ - Claude Code: `/sellable:refill-sends`
61
+ - Codex: `$sellable:refill-sends`
62
+
63
+ Accepted invocation flags in the same user request:
64
+
65
+ - `--yolo`: auto-accept the rendered bounded refill packet after the required
66
+ fresh state reread.
67
+ - `--sender <name-or-id>`: scope to a specific sender; repeat for multiple
68
+ senders.
69
+ - `senderIds: <id>, <id>` or `senderNames: <name>, <name>`: explicit selector
70
+ alternatives when the host preserves natural-language arguments better than
71
+ shell-style flags.
72
+
73
+ When the host can call typed MCP tools, start with:
74
+
75
+ ```text
76
+ refill_sends({ yolo?: boolean, senders?: string[], senderIds?: string[], senderNames?: string[], horizonSendDays?: number })
77
+ ```
78
+
79
+ That command helper only normalizes arguments and returns the execution
80
+ contract. It does not mutate. Continue with the workflow below for route
81
+ selection, state rereads, approval gating, source import, preparation, and
82
+ bounded approval.
83
+
84
+ First call `get_auth_status({})`. If auth or active workspace is not OK, follow
85
+ the returned login/workspace guidance before route resolution. Do not run refill
86
+ research against an implicit or guessed workspace.
50
87
 
51
88
  Treat "refill senders", "fill senders", "load everyone up", and "max out
52
89
  senders" as sender-scoped requests. The target set is senders enrolled in active