@sellable/mcp 0.1.446 → 0.1.448
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 +33 -5
- package/dist/api.d.ts +5 -2
- package/dist/api.js +10 -8
- package/dist/index-dev.js +0 -0
- package/dist/index.js +0 -0
- package/dist/server.js +4 -1
- package/dist/tools/registry.d.ts +22 -1
- package/dist/tools/workspaces.d.ts +52 -1
- package/dist/tools/workspaces.js +24 -4
- package/package.json +1 -1
- package/skills/refresh-sender-engagement/SKILL.md +66 -12
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
|
|
19
|
+
There are eight 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 seven public Sellable entrypoints shared across hosts:
|
|
|
24
24
|
- `sellable:foundation`
|
|
25
25
|
- `sellable:content`
|
|
26
26
|
- `sellable:create-post`
|
|
27
|
+
- `sellable:refresh-sender-engagement`
|
|
27
28
|
- `sellable:refill-sends`
|
|
28
29
|
|
|
29
30
|
The create-campaign public wrapper at
|
|
@@ -64,6 +65,13 @@ reader value, validates proof/AI tells, and saves content artifacts under
|
|
|
64
65
|
|
|
65
66
|
- `mcp/sellable/skills/create-post/SKILL.md`
|
|
66
67
|
|
|
68
|
+
The refresh-sender-engagement public command wrapper finds active sender-owned
|
|
69
|
+
Post Engagers / Signal Discovery campaigns, refreshes recent sender-authored
|
|
70
|
+
posts, pulls latest engagers, filters to ICP, and adds net-new leads without
|
|
71
|
+
sending from:
|
|
72
|
+
|
|
73
|
+
- `mcp/sellable/skills/refresh-sender-engagement/SKILL.md`
|
|
74
|
+
|
|
67
75
|
The refill-sends public command wrapper plans and executes approval-gated send
|
|
68
76
|
refills. It supports `--yolo` and optional sender selectors such as
|
|
69
77
|
`--sender "Christian Reyes"`, optional through-date selectors such as
|
|
@@ -195,10 +203,12 @@ The installer does the full local setup:
|
|
|
195
203
|
After the installer passes, fully quit and reopen Codex Desktop. Start a new
|
|
196
204
|
thread and select `Sellable Create Campaign`, `Sellable Create A/B Test`,
|
|
197
205
|
`Sellable Create Evergreen Campaigns`, `Sellable Foundation`,
|
|
198
|
-
`Sellable Content`, `Sellable Create Post`,
|
|
206
|
+
`Sellable Content`, `Sellable Create Post`, `Sellable Refresh Sender Engagement`,
|
|
207
|
+
or `Sellable Refill Sends`; or invoke
|
|
199
208
|
`$sellable:create-campaign`, `$sellable:create-ab-test`,
|
|
200
209
|
`$sellable:create-evergreen-campaigns`, `$sellable:foundation`,
|
|
201
|
-
`$sellable:content`, `$sellable:create-post`,
|
|
210
|
+
`$sellable:content`, `$sellable:create-post`,
|
|
211
|
+
`$sellable:refresh-sender-engagement`, or `$sellable:refill-sends`. If the app still says
|
|
202
212
|
`mcp__sellable__*` tools are missing after the installer passes, check that
|
|
203
213
|
`~/.codex/config.toml` contains both `[marketplaces.sellable]` and
|
|
204
214
|
`[plugins."sellable@sellable"]`.
|
|
@@ -215,6 +225,7 @@ Use these names consistently:
|
|
|
215
225
|
- Claude Code command: `/sellable:foundation`
|
|
216
226
|
- Claude Code command: `/sellable:content`
|
|
217
227
|
- Claude Code command: `/sellable:create-post`
|
|
228
|
+
- Claude Code command: `/sellable:refresh-sender-engagement`
|
|
218
229
|
- Claude Code command: `/sellable:refill-sends`
|
|
219
230
|
- Codex command: `$sellable:create-campaign`
|
|
220
231
|
- Codex command: `$sellable:create-ab-test`
|
|
@@ -222,6 +233,7 @@ Use these names consistently:
|
|
|
222
233
|
- Codex command: `$sellable:foundation`
|
|
223
234
|
- Codex command: `$sellable:content`
|
|
224
235
|
- Codex command: `$sellable:create-post`
|
|
236
|
+
- Codex command: `$sellable:refresh-sender-engagement`
|
|
225
237
|
- Codex command: `$sellable:refill-sends`
|
|
226
238
|
- Codex Desktop plugin: `sellable@sellable`
|
|
227
239
|
- Codex visible skill: `Sellable Create Campaign`
|
|
@@ -230,6 +242,7 @@ Use these names consistently:
|
|
|
230
242
|
- Codex visible skill: `Sellable Foundation`
|
|
231
243
|
- Codex visible skill: `Sellable Content`
|
|
232
244
|
- Codex visible skill: `Sellable Create Post`
|
|
245
|
+
- Codex visible skill: `Sellable Refresh Sender Engagement`
|
|
233
246
|
- Codex visible skill: `Sellable Refill Sends`
|
|
234
247
|
- Codex skill frontmatter name: `create-campaign`
|
|
235
248
|
- Codex skill frontmatter name: `create-ab-test`
|
|
@@ -237,6 +250,7 @@ Use these names consistently:
|
|
|
237
250
|
- Codex skill frontmatter name: `foundation`
|
|
238
251
|
- Codex skill frontmatter name: `content`
|
|
239
252
|
- Codex skill frontmatter name: `create-post`
|
|
253
|
+
- Codex skill frontmatter name: `refresh-sender-engagement`
|
|
240
254
|
- Codex skill frontmatter name: `refill-sends`
|
|
241
255
|
- MCP server name: `sellable`
|
|
242
256
|
- Internal workflow prompt: `create-campaign-v2`
|
|
@@ -301,6 +315,13 @@ Use the refill command for sender send refills:
|
|
|
301
315
|
/sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"
|
|
302
316
|
```
|
|
303
317
|
|
|
318
|
+
Use the refresh command to top up sender-owned post-engager campaigns from the
|
|
319
|
+
latest relevant sender-authored posts:
|
|
320
|
+
|
|
321
|
+
```
|
|
322
|
+
/sellable:refresh-sender-engagement --sender "Christian Reyes"
|
|
323
|
+
```
|
|
324
|
+
|
|
304
325
|
Then describe intent naturally, for example:
|
|
305
326
|
|
|
306
327
|
- "Let's make a campaign with sellable"
|
|
@@ -329,6 +350,12 @@ $sellable:refill-sends --yolo --until 2026-06-30
|
|
|
329
350
|
$sellable:refill-sends --sender "Christian Reyes" --sender "Thomas Nobbs"
|
|
330
351
|
```
|
|
331
352
|
|
|
353
|
+
Use the Codex refresh command for latest post engagers:
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
$sellable:refresh-sender-engagement --sender "Christian Reyes"
|
|
357
|
+
```
|
|
358
|
+
|
|
332
359
|
Installed skill package path:
|
|
333
360
|
|
|
334
361
|
- `~/.codex/plugins/cache/sellable/sellable/<version>/skills/sellable-create-campaign/SKILL.md`
|
|
@@ -494,9 +521,10 @@ compatibility and as the tested foundation-memory engine.
|
|
|
494
521
|
|
|
495
522
|
- `list_workspaces` - List accessible workspaces
|
|
496
523
|
- `get_active_workspace` - Show active workspace selection
|
|
524
|
+
- `get_workspace` - Show workspace members and pending invites
|
|
497
525
|
- `set_active_workspace` - Set active workspace by ID
|
|
498
|
-
- `create_workspace` - Create a new workspace
|
|
499
|
-
- `add_teammate` - Invite a teammate
|
|
526
|
+
- `create_workspace` - Create a new workspace and make it active
|
|
527
|
+
- `add_teammate` - Invite a teammate to the active workspace or a provided `workspaceId`
|
|
500
528
|
|
|
501
529
|
### Campaign Tools (Free)
|
|
502
530
|
|
package/dist/api.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export interface DownloadToFileResult {
|
|
|
8
8
|
contentType: string | null;
|
|
9
9
|
status: number;
|
|
10
10
|
}
|
|
11
|
+
export interface ApiRequestOptions {
|
|
12
|
+
workspaceId?: string | null;
|
|
13
|
+
}
|
|
11
14
|
export declare class SellableApiError extends Error {
|
|
12
15
|
status: number;
|
|
13
16
|
body: string;
|
|
@@ -19,10 +22,10 @@ export declare class SellableApi {
|
|
|
19
22
|
private buildError;
|
|
20
23
|
private requestResponse;
|
|
21
24
|
private request;
|
|
22
|
-
get<T>(path: string): Promise<T>;
|
|
25
|
+
get<T>(path: string, options?: ApiRequestOptions): Promise<T>;
|
|
23
26
|
getText(path: string): Promise<string>;
|
|
24
27
|
downloadToFile(requestPath: string, destinationPath: string): Promise<DownloadToFileResult>;
|
|
25
|
-
post<T>(path: string, body?: object): Promise<T>;
|
|
28
|
+
post<T>(path: string, body?: object, options?: ApiRequestOptions): Promise<T>;
|
|
26
29
|
put<T>(path: string, body?: object): Promise<T>;
|
|
27
30
|
patch<T>(path: string, body?: object): Promise<T>;
|
|
28
31
|
delete<T>(path: string): Promise<T>;
|
package/dist/api.js
CHANGED
|
@@ -35,11 +35,13 @@ export class SellableApi {
|
|
|
35
35
|
: undefined;
|
|
36
36
|
return new SellableApiError(status, errorText, guidance);
|
|
37
37
|
}
|
|
38
|
-
async requestResponse(method, path, body) {
|
|
38
|
+
async requestResponse(method, path, body, options) {
|
|
39
39
|
// Re-read config on every request so workspace switches take effect immediately
|
|
40
40
|
const config = getConfig();
|
|
41
41
|
const url = `${config.apiUrl}${path}`;
|
|
42
|
-
const workspaceId =
|
|
42
|
+
const workspaceId = options && Object.prototype.hasOwnProperty.call(options, "workspaceId")
|
|
43
|
+
? options.workspaceId
|
|
44
|
+
: config.activeWorkspaceId || config.workspaceId || null;
|
|
43
45
|
const response = await fetch(url, {
|
|
44
46
|
method,
|
|
45
47
|
headers: {
|
|
@@ -55,12 +57,12 @@ export class SellableApi {
|
|
|
55
57
|
}
|
|
56
58
|
return response;
|
|
57
59
|
}
|
|
58
|
-
async request(method, path, body) {
|
|
59
|
-
const response = await this.requestResponse(method, path, body);
|
|
60
|
+
async request(method, path, body, options) {
|
|
61
|
+
const response = await this.requestResponse(method, path, body, options);
|
|
60
62
|
return response.json();
|
|
61
63
|
}
|
|
62
|
-
async get(path) {
|
|
63
|
-
return this.request("GET", path);
|
|
64
|
+
async get(path, options) {
|
|
65
|
+
return this.request("GET", path, undefined, options);
|
|
64
66
|
}
|
|
65
67
|
async getText(path) {
|
|
66
68
|
const response = await this.requestResponse("GET", path);
|
|
@@ -93,8 +95,8 @@ export class SellableApi {
|
|
|
93
95
|
}
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
|
-
async post(path, body) {
|
|
97
|
-
return this.request("POST", path, body);
|
|
98
|
+
async post(path, body, options) {
|
|
99
|
+
return this.request("POST", path, body, options);
|
|
98
100
|
}
|
|
99
101
|
async put(path, body) {
|
|
100
102
|
return this.request("PUT", path, body);
|
package/dist/index-dev.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/server.js
CHANGED
|
@@ -50,7 +50,7 @@ import { handleVerifyTableRow } from "./tools/verify-row.js";
|
|
|
50
50
|
import { sanitizeWatchUrlsForMcpResult } from "./tools/watch-url-security.js";
|
|
51
51
|
import { getCampaignWaterfall, setCampaignWaterfallOrder, } from "./tools/waterfalls.js";
|
|
52
52
|
import { exportWorkspaceCsv } from "./tools/workspace-export.js";
|
|
53
|
-
import { addTeammate, createWorkspace, getActiveWorkspace, listWorkspaces, setActiveWorkspace, } from "./tools/workspaces.js";
|
|
53
|
+
import { addTeammate, createWorkspace, getActiveWorkspace, getWorkspace, listWorkspaces, setActiveWorkspace, } from "./tools/workspaces.js";
|
|
54
54
|
import { checkForUpdates, logUpdateNotice } from "./update-check.js";
|
|
55
55
|
const server = new Server({
|
|
56
56
|
name: "sellable-mcp",
|
|
@@ -179,6 +179,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
179
179
|
case "get_active_workspace":
|
|
180
180
|
result = getActiveWorkspace();
|
|
181
181
|
break;
|
|
182
|
+
case "get_workspace":
|
|
183
|
+
result = await getWorkspace(args?.workspaceId);
|
|
184
|
+
break;
|
|
182
185
|
case "set_active_workspace":
|
|
183
186
|
result = await setActiveWorkspace(args?.workspaceId, args?.userConfirmed);
|
|
184
187
|
break;
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -7612,6 +7612,25 @@ export declare const allTools: ({
|
|
|
7612
7612
|
readonly required: readonly ["waterfallKey", "orderedSlotKeys"];
|
|
7613
7613
|
readonly additionalProperties: false;
|
|
7614
7614
|
};
|
|
7615
|
+
} | {
|
|
7616
|
+
name: string;
|
|
7617
|
+
description: string;
|
|
7618
|
+
inputSchema: {
|
|
7619
|
+
type: string;
|
|
7620
|
+
properties: {
|
|
7621
|
+
workspaceId: {
|
|
7622
|
+
type: string;
|
|
7623
|
+
};
|
|
7624
|
+
userConfirmed?: undefined;
|
|
7625
|
+
name?: undefined;
|
|
7626
|
+
email?: undefined;
|
|
7627
|
+
role?: undefined;
|
|
7628
|
+
redirectTo?: undefined;
|
|
7629
|
+
campaignId?: undefined;
|
|
7630
|
+
};
|
|
7631
|
+
required: string[];
|
|
7632
|
+
additionalProperties: boolean;
|
|
7633
|
+
};
|
|
7615
7634
|
} | {
|
|
7616
7635
|
name: string;
|
|
7617
7636
|
description: string;
|
|
@@ -7659,6 +7678,9 @@ export declare const allTools: ({
|
|
|
7659
7678
|
inputSchema: {
|
|
7660
7679
|
type: string;
|
|
7661
7680
|
properties: {
|
|
7681
|
+
workspaceId: {
|
|
7682
|
+
type: string;
|
|
7683
|
+
};
|
|
7662
7684
|
email: {
|
|
7663
7685
|
type: string;
|
|
7664
7686
|
};
|
|
@@ -7672,7 +7694,6 @@ export declare const allTools: ({
|
|
|
7672
7694
|
campaignId: {
|
|
7673
7695
|
type: string;
|
|
7674
7696
|
};
|
|
7675
|
-
workspaceId?: undefined;
|
|
7676
7697
|
userConfirmed?: undefined;
|
|
7677
7698
|
name?: undefined;
|
|
7678
7699
|
};
|
|
@@ -6,6 +6,32 @@ type WorkspaceSummary = {
|
|
|
6
6
|
isDefault: boolean;
|
|
7
7
|
createdAt: string;
|
|
8
8
|
};
|
|
9
|
+
type WorkspaceDetails = {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
slug: string;
|
|
13
|
+
credits: number;
|
|
14
|
+
role: string;
|
|
15
|
+
createdAt: string;
|
|
16
|
+
updatedAt: string;
|
|
17
|
+
archivedAt: string | null;
|
|
18
|
+
members: Array<{
|
|
19
|
+
id: string;
|
|
20
|
+
userId: string;
|
|
21
|
+
email: string;
|
|
22
|
+
role: string;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
}>;
|
|
25
|
+
pendingInvites: Array<{
|
|
26
|
+
id: string;
|
|
27
|
+
email: string;
|
|
28
|
+
role: string;
|
|
29
|
+
invitedByEmail: string | null;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
expiresAt: string;
|
|
32
|
+
redirectTo: string | null;
|
|
33
|
+
}>;
|
|
34
|
+
};
|
|
9
35
|
export declare const workspaceToolDefinitions: ({
|
|
10
36
|
name: string;
|
|
11
37
|
description: string;
|
|
@@ -23,6 +49,25 @@ export declare const workspaceToolDefinitions: ({
|
|
|
23
49
|
required: never[];
|
|
24
50
|
additionalProperties: boolean;
|
|
25
51
|
};
|
|
52
|
+
} | {
|
|
53
|
+
name: string;
|
|
54
|
+
description: string;
|
|
55
|
+
inputSchema: {
|
|
56
|
+
type: string;
|
|
57
|
+
properties: {
|
|
58
|
+
workspaceId: {
|
|
59
|
+
type: string;
|
|
60
|
+
};
|
|
61
|
+
userConfirmed?: undefined;
|
|
62
|
+
name?: undefined;
|
|
63
|
+
email?: undefined;
|
|
64
|
+
role?: undefined;
|
|
65
|
+
redirectTo?: undefined;
|
|
66
|
+
campaignId?: undefined;
|
|
67
|
+
};
|
|
68
|
+
required: string[];
|
|
69
|
+
additionalProperties: boolean;
|
|
70
|
+
};
|
|
26
71
|
} | {
|
|
27
72
|
name: string;
|
|
28
73
|
description: string;
|
|
@@ -70,6 +115,9 @@ export declare const workspaceToolDefinitions: ({
|
|
|
70
115
|
inputSchema: {
|
|
71
116
|
type: string;
|
|
72
117
|
properties: {
|
|
118
|
+
workspaceId: {
|
|
119
|
+
type: string;
|
|
120
|
+
};
|
|
73
121
|
email: {
|
|
74
122
|
type: string;
|
|
75
123
|
};
|
|
@@ -83,7 +131,6 @@ export declare const workspaceToolDefinitions: ({
|
|
|
83
131
|
campaignId: {
|
|
84
132
|
type: string;
|
|
85
133
|
};
|
|
86
|
-
workspaceId?: undefined;
|
|
87
134
|
userConfirmed?: undefined;
|
|
88
135
|
name?: undefined;
|
|
89
136
|
};
|
|
@@ -98,6 +145,9 @@ export declare function getActiveWorkspace(): {
|
|
|
98
145
|
activeWorkspaceId: string | null;
|
|
99
146
|
activeWorkspaceName: string | null;
|
|
100
147
|
};
|
|
148
|
+
export declare function getWorkspace(workspaceId: string): Promise<{
|
|
149
|
+
workspace: WorkspaceDetails;
|
|
150
|
+
}>;
|
|
101
151
|
export declare function setActiveWorkspace(workspaceId: string, userConfirmed?: boolean): Promise<{
|
|
102
152
|
ok: boolean;
|
|
103
153
|
error: string;
|
|
@@ -132,6 +182,7 @@ export declare function createWorkspace(name: string): Promise<{
|
|
|
132
182
|
activeWorkspaceId: string;
|
|
133
183
|
}>;
|
|
134
184
|
export declare function addTeammate(input: {
|
|
185
|
+
workspaceId?: string;
|
|
135
186
|
email: string;
|
|
136
187
|
role?: "ADMIN" | "MEMBER";
|
|
137
188
|
redirectTo?: string;
|
package/dist/tools/workspaces.js
CHANGED
|
@@ -21,6 +21,18 @@ export const workspaceToolDefinitions = [
|
|
|
21
21
|
additionalProperties: false,
|
|
22
22
|
},
|
|
23
23
|
},
|
|
24
|
+
{
|
|
25
|
+
name: "get_workspace",
|
|
26
|
+
description: "Get details of an accessible workspace including members and pending invites.",
|
|
27
|
+
inputSchema: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: {
|
|
30
|
+
workspaceId: { type: "string" },
|
|
31
|
+
},
|
|
32
|
+
required: ["workspaceId"],
|
|
33
|
+
additionalProperties: false,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
24
36
|
{
|
|
25
37
|
name: "set_active_workspace",
|
|
26
38
|
description: "Set active workspace by ID. Only call this when the user explicitly asks to switch workspace.",
|
|
@@ -39,7 +51,7 @@ export const workspaceToolDefinitions = [
|
|
|
39
51
|
},
|
|
40
52
|
{
|
|
41
53
|
name: "create_workspace",
|
|
42
|
-
description: "Create a new workspace.",
|
|
54
|
+
description: "Create a new workspace. The authenticated user becomes OWNER and the new workspace becomes active for subsequent active-workspace tools.",
|
|
43
55
|
inputSchema: {
|
|
44
56
|
type: "object",
|
|
45
57
|
properties: {
|
|
@@ -51,10 +63,11 @@ export const workspaceToolDefinitions = [
|
|
|
51
63
|
},
|
|
52
64
|
{
|
|
53
65
|
name: "add_teammate",
|
|
54
|
-
description: "Invite a teammate to the active workspace.",
|
|
66
|
+
description: "Invite a teammate to a workspace. Defaults to the active workspace; pass workspaceId to invite to a specific accessible workspace without switching active workspace.",
|
|
55
67
|
inputSchema: {
|
|
56
68
|
type: "object",
|
|
57
69
|
properties: {
|
|
70
|
+
workspaceId: { type: "string" },
|
|
58
71
|
email: { type: "string" },
|
|
59
72
|
role: { type: "string", enum: ["ADMIN", "MEMBER"] },
|
|
60
73
|
redirectTo: { type: "string" },
|
|
@@ -77,6 +90,11 @@ export function getActiveWorkspace() {
|
|
|
77
90
|
activeWorkspaceName: config.activeWorkspaceName || null,
|
|
78
91
|
};
|
|
79
92
|
}
|
|
93
|
+
export async function getWorkspace(workspaceId) {
|
|
94
|
+
const api = getApi();
|
|
95
|
+
const { workspace } = await api.get(`/api/v3/workspaces/${encodeURIComponent(workspaceId)}`);
|
|
96
|
+
return { workspace };
|
|
97
|
+
}
|
|
80
98
|
export async function setActiveWorkspace(workspaceId, userConfirmed) {
|
|
81
99
|
const api = getApi();
|
|
82
100
|
const { workspaces } = await api.get("/api/v3/workspaces");
|
|
@@ -126,8 +144,9 @@ export async function createWorkspace(name) {
|
|
|
126
144
|
};
|
|
127
145
|
}
|
|
128
146
|
export async function addTeammate(input) {
|
|
147
|
+
const args = input || {};
|
|
129
148
|
const config = getConfig();
|
|
130
|
-
const workspaceId = config.activeWorkspaceId || config.workspaceId;
|
|
149
|
+
const workspaceId = args.workspaceId || config.activeWorkspaceId || config.workspaceId;
|
|
131
150
|
if (!workspaceId) {
|
|
132
151
|
return {
|
|
133
152
|
ok: false,
|
|
@@ -135,5 +154,6 @@ export async function addTeammate(input) {
|
|
|
135
154
|
};
|
|
136
155
|
}
|
|
137
156
|
const api = getApi();
|
|
138
|
-
|
|
157
|
+
const { workspaceId: _workspaceId, ...inviteInput } = args;
|
|
158
|
+
return api.post("/api/v3/workspaces/invites", inviteInput, { workspaceId });
|
|
139
159
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: refresh-sender-engagement
|
|
3
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:
|
|
4
|
+
visibility: public
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- mcp__sellable__get_auth_status
|
|
7
|
+
- mcp__sellable__start_cli_login
|
|
8
|
+
- mcp__sellable__wait_for_cli_login
|
|
9
|
+
- mcp__sellable__get_active_workspace
|
|
10
|
+
- mcp__sellable__list_workspaces
|
|
11
|
+
- mcp__sellable__set_active_workspace
|
|
12
|
+
- mcp__sellable__get_subskill_prompt
|
|
13
|
+
- mcp__sellable__search_subskill_prompts
|
|
14
|
+
- mcp__sellable__list_senders
|
|
15
|
+
- mcp__sellable__get_sender
|
|
16
|
+
- mcp__sellable__get_campaigns
|
|
17
|
+
- mcp__sellable__get_campaign
|
|
18
|
+
- mcp__sellable__get_campaign_context
|
|
19
|
+
- mcp__sellable__get_campaign_table_schema
|
|
20
|
+
- mcp__sellable__list_tables
|
|
21
|
+
- mcp__sellable__get_rows_minimal
|
|
22
|
+
- mcp__sellable__fetch_linkedin_posts
|
|
23
|
+
- mcp__sellable__select_promising_posts
|
|
24
|
+
- mcp__sellable__fetch_post_engagers
|
|
25
|
+
- mcp__sellable__add_on_demand_leads
|
|
5
26
|
---
|
|
6
27
|
|
|
7
28
|
# Refresh Sender Engagement
|
|
@@ -11,27 +32,60 @@ You are a pipeline supply agent. People who engage with a sender's LinkedIn post
|
|
|
11
32
|
</role>
|
|
12
33
|
|
|
13
34
|
<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
|
|
35
|
+
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, inspect the active workspace and refresh every connected sender that has an active/paused sender-owned Post Engagers campaign backed by Signal Discovery.
|
|
15
36
|
|
|
16
|
-
Optional: lookback window (default: posts from the last 30 days), engagement sources (default `both` reactions+comments),
|
|
37
|
+
Optional: lookback window (default: posts from the last 30 days), engagement sources (default `both` reactions+comments), target sender names/ids, maximum posts per sender (default 5, hard cap 5 unless the user explicitly asks for more), and target campaign ids/names when the user wants to force a specific campaign.
|
|
17
38
|
</inputs>
|
|
18
39
|
|
|
40
|
+
<entrypoint>
|
|
41
|
+
This is a public Sellable command:
|
|
42
|
+
|
|
43
|
+
- Claude Code: `/sellable:refresh-sender-engagement`
|
|
44
|
+
- Codex: `$sellable:refresh-sender-engagement`
|
|
45
|
+
|
|
46
|
+
Use this command when the user asks to refresh recent engagers, top up tracked
|
|
47
|
+
campaign post engagers, pull latest engagers from sender posts, or refill warm
|
|
48
|
+
post-engager source rows. It is not a send-refill command; if the user asks to
|
|
49
|
+
prepare/schedule sends after adding rows, finish this refresh first and then
|
|
50
|
+
suggest `refill-sends`.
|
|
51
|
+
</entrypoint>
|
|
52
|
+
|
|
19
53
|
<objective>
|
|
20
|
-
For each sender:
|
|
21
|
-
|
|
22
|
-
1. **Find
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
54
|
+
For each target sender/campaign:
|
|
55
|
+
|
|
56
|
+
1. **Find active Signal Discovery/Post Engagers campaigns first**:
|
|
57
|
+
- Call `get_auth_status` and confirm the active workspace.
|
|
58
|
+
- Call `get_campaigns` and, when needed, `list_tables`/`get_campaign` to find candidate campaigns.
|
|
59
|
+
- Keep only active or paused campaign-backed sender-owned Post Engagers campaigns. Strong signals include campaign/table names like `<Sender> - Post Engagers`, `sourceProvider:"signal-discovery"`, sender attachment to exactly one sender, and source/list/table readback indicating post engagers.
|
|
60
|
+
- Exclude shared Signal Discovery lanes, Shared Cold Fallback lanes, archived/completed campaigns, non-campaign tables, direct/on-demand-only campaigns, and any campaign attached to multiple senders unless the user explicitly selected it and the readback proves it is sender-owned.
|
|
61
|
+
- If no matching campaign exists for a sender, report "no active Post Engagers Signal Discovery campaign — create one first" and skip; do not silently create campaigns.
|
|
62
|
+
2. **Resolve the sender and source boundary**:
|
|
63
|
+
- Match each candidate campaign to its sender from `list_senders`/`get_sender`.
|
|
64
|
+
- Use the sender's own LinkedIn profile URL/handle as the only source author boundary.
|
|
65
|
+
- Never scrape third-party authors into a sender-owned Post Engagers campaign.
|
|
66
|
+
3. **Find relevant sender-authored posts to refresh**:
|
|
67
|
+
- Call `fetch_linkedin_posts({ linkedinUrl: sender profile, limit: 25 })`.
|
|
68
|
+
- Keep original posts authored by that exact sender, not reposts, from the lookback window.
|
|
69
|
+
- Rank posts by recency, engagement count, and fit to the campaign's buyer/problem/topic. Prefer posts likely to attract the target buyer over generic company updates.
|
|
70
|
+
- If the campaign has an existing Signal Discovery/source state that names tracked/selected posts, prefer refreshing those posts when they are still inside the lookback window and relevant; otherwise choose the strongest recent sender-authored posts.
|
|
71
|
+
- When the product flow expects selected posts to be visible, call `select_promising_posts` before scraping.
|
|
72
|
+
4. **Pull latest engagers**:
|
|
73
|
+
- For the top posts (up to 5 per sender per run), call `fetch_post_engagers({ postUrl, sources })`.
|
|
74
|
+
- Default `sources` to `"both"` unless the user requested reactions-only or comments-only.
|
|
75
|
+
5. **Filter to ICP** using the campaign's existing headline ICP criteria (from `get_campaign` brief/rubrics/table schema). Judge each engager's headline against those criteria; exclude obvious non-fits, the sender's own colleagues, existing employees, students/job-seekers, competitors, and anyone with no usable headline. When the campaign has no criteria, keep likely decision-makers/operators and exclude weak-fit profiles.
|
|
76
|
+
6. **Add net-new leads only**:
|
|
77
|
+
- Use `add_on_demand_leads({ tableId, leads, skipDuplicates: true })` with name, headline-derived title, profile URL, and source/post context where the tool accepts it.
|
|
78
|
+
- Dedupe is mandatory. Never disable dedupe on a scheduled run.
|
|
79
|
+
- Do not generate, approve, schedule, or send messages.
|
|
80
|
+
7. **Report**: campaigns inspected, target campaigns selected, posts scanned, engagers found, ICP-passing, net-new added per sender/campaign. 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
81
|
</objective>
|
|
29
82
|
|
|
30
83
|
<safety>
|
|
31
84
|
- 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
85
|
- Respect workspace boundaries: only add leads to campaigns in the active workspace, and only for senders that belong to it.
|
|
86
|
+
- Respect campaign boundaries: only add engagers to the matched sender-owned Post Engagers campaign/table. Do not mix shared-lane engagers into sender-owned campaigns or sender-owned engagers into shared lanes.
|
|
33
87
|
- 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/
|
|
88
|
+
- Never call `start_campaign`, `attach_sequence`, `queue_campaign_cells`, `start_campaign_message_preparation`, approval tools, or any send/schedule tool.
|
|
35
89
|
</safety>
|
|
36
90
|
|
|
37
91
|
<output>
|