@sellable/mcp 0.1.512 → 0.1.513

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/dist/api.js CHANGED
@@ -1,9 +1,9 @@
1
- import { getConfig, getConfigPath } from "./auth.js";
2
1
  import { createWriteStream } from "node:fs";
3
2
  import { mkdir, rename, rm, stat } from "node:fs/promises";
4
3
  import path from "node:path";
5
4
  import { Readable } from "node:stream";
6
5
  import { pipeline } from "node:stream/promises";
6
+ import { getConfig, getConfigPath } from "./auth.js";
7
7
  export class SellableApiError extends Error {
8
8
  status;
9
9
  body;
@@ -21,18 +21,21 @@ export class SellableApiError extends Error {
21
21
  export class SellableApi {
22
22
  buildError(status, errorText) {
23
23
  const isAuthError = status === 401 || status === 403;
24
+ const isWorkspaceMembershipError = status === 403 && errorText.includes("No access to workspace");
24
25
  const missingWorkspace = status === 400 && errorText.includes("Workspace");
25
- const guidance = isAuthError
26
- ? "Sellable authentication failed.\n\n" +
27
- "Run the first-run Sellable login flow from a Sellable workflow, then retry.\n\n" +
28
- "If the browser login page shows a manual fallback command, use:\n" +
29
- "sellable auth set <token> --workspace-id <workspace_id>\n\n" +
30
- `Current config path: ${getConfigPath()}\n\n` +
31
- "Older copied Settings tokens can be stale, restricted, or missing write/credit permissions. Sign in again so Sellable mints the current agent token."
32
- : missingWorkspace
33
- ? "No active workspace selected.\n\n" +
34
- "Run list_workspaces then set_active_workspace to choose a workspace."
35
- : undefined;
26
+ const guidance = isWorkspaceMembershipError
27
+ ? "The authenticated user is not a member of this workspace. Confirm the workspaceId or ask a workspace admin to add the user; re-login will not help."
28
+ : isAuthError
29
+ ? "Sellable authentication failed.\n\n" +
30
+ "Run the first-run Sellable login flow from a Sellable workflow, then retry.\n\n" +
31
+ "If the browser login page shows a manual fallback command, use:\n" +
32
+ "sellable auth set <token> --workspace-id <workspace_id>\n\n" +
33
+ `Current config path: ${getConfigPath()}\n\n` +
34
+ "Older copied Settings tokens can be stale, restricted, or missing write/credit permissions. Sign in again so Sellable mints the current agent token."
35
+ : missingWorkspace
36
+ ? "No active workspace selected.\n\n" +
37
+ "Run list_workspaces then set_active_workspace to choose a workspace."
38
+ : undefined;
36
39
  return new SellableApiError(status, errorText, guidance);
37
40
  }
38
41
  async requestResponse(method, path, body, options) {
@@ -74,7 +74,7 @@ export function createRunJournal(params) {
74
74
  }
75
75
  const startedAt = (params.now ?? new Date()).toISOString();
76
76
  const header = [
77
- `# Refill Sends Evergreen Run ${runId}`,
77
+ `# Refill Sends V2 Run ${runId}`,
78
78
  "",
79
79
  `- Run ID: ${runId}`,
80
80
  `- Workspace ID: ${params.workspaceId}`,
package/dist/server.js CHANGED
@@ -9,12 +9,8 @@ import { prepareCampaignAbTest } from "./tools/campaign-ab-test.js";
9
9
  import { resolveCampaignFillRoute } from "./tools/campaign-fill-routing.js";
10
10
  import { fillCampaignHorizon } from "./tools/campaign-horizon-fill.js";
11
11
  import { cancelPrepareCampaignMessages, getPrepareCampaignMessagesStatus, startPrepareCampaignMessages, } from "./tools/campaign-message-preparation.js";
12
- import { getCampaignRefillState } from "./tools/campaign-refill-state.js";
13
- import { getEvergreenRefillPlan } from "./tools/evergreen-refill-plan.js";
14
- import { getRefillTargetPlan } from "./tools/refill-target-plan.js";
15
- import { refillSendsEvergreenCommand } from "./tools/refill-sends-evergreen.js";
16
- import { getSchedulerFillCapacity } from "./tools/scheduler-fill-capacity.js";
17
12
  import { getCampaignTableSchema, queueCampaignCells, recordCampaignReviewBatch, reviseMessageTemplateAndRerun, selectCampaignCells, waitForCampaignProcessing, } from "./tools/campaign-processing.js";
13
+ import { getCampaignRefillState } from "./tools/campaign-refill-state.js";
18
14
  import { archiveCampaign, createCampaign, duplicateCampaign, getCampaign, getCampaignMessagesPreview, getCampaigns, pauseCampaign, startCampaign, updateCampaign, updateCampaignBrief, } from "./tools/campaigns.js";
19
15
  import { queueCells, updateCell } from "./tools/cells.js";
20
16
  import { handleStartCliLogin, handleWaitForCliLogin, } from "./tools/cli-login.js";
@@ -31,6 +27,7 @@ import { searchEngagementPosts } from "./tools/engage-discovery.js";
31
27
  import { copySenderConfigTool, getEngageMemoryTool, migrateFlatConfigsTool, recordEngageProvenSearchTool, setEngageStyleGuideTool, upsertEngageTrackedPersonTool, } from "./tools/engage-memory.js";
32
28
  import { getEngageStateTool, setEngageStateTool, } from "./tools/engage-state.js";
33
29
  import { bulkEnrichWithProspeo, enrichWithProspeo, getProspeoCredits, } from "./tools/enrichment.js";
30
+ import { getRefillPlanV2 } from "./tools/evergreen-refill-plan.js";
34
31
  import { getCampaignFramework } from "./tools/framework.js";
35
32
  import { confirmHarvestJobCompanies, searchHarvestJobs, } from "./tools/harvest-jobs.js";
36
33
  import { checkInboxReplyEligibility, getInboxThread, searchInboxThreads, sendInboxDraft, sendInboxManualReply, updateInboxDraft, } from "./tools/inbox.js";
@@ -41,10 +38,13 @@ import { addOnDemandLeads, createOnDemandCampaign, createOnDemandTable, initOnDe
41
38
  import { upsertRubric } from "./tools/processing.js";
42
39
  import { completeSenderResearch, getPostFindLeadsScoutRegistry, getSourceScoutRegistry, getSubskillAsset, getSubskillPrompt, listSubskillPrompts, searchSubskillPrompts, } from "./tools/prompts.js";
43
40
  import { waitForCampaignTableReady, waitForLeadListReady, } from "./tools/readiness.js";
41
+ import { refillSendsV2Command } from "./tools/refill-sends-v2.js";
44
42
  import { executeRefillSendsCommand } from "./tools/refill-sends.js";
43
+ import { getRefillTargetPlan } from "./tools/refill-target-plan.js";
45
44
  import { allTools } from "./tools/registry.js";
46
45
  import { getRows, getTableRows, getTableRowsMinimal } from "./tools/rows.js";
47
46
  import { addRubricItem, checkRubric, deleteRubricItem, draftRubrics, saveRubrics, selectNecessaryRubrics, updateRubricItem, waitForRubricResults, } from "./tools/rubrics.js";
47
+ import { getSchedulerFillCapacity } from "./tools/scheduler-fill-capacity.js";
48
48
  import { getSenderRoutingTool, setSenderRoutingTool, } from "./tools/sender-routing.js";
49
49
  import { getSender, listSenders, refreshPaidInmailCredits, } from "./tools/senders.js";
50
50
  import { attachRecommendedSequence, attachSequence, createWorkflowTable, } from "./tools/sequencer.js";
@@ -225,8 +225,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
225
225
  case "get_campaign_refill_state":
226
226
  result = await getCampaignRefillState(args);
227
227
  break;
228
+ case "get_refill_plan_v2":
228
229
  case "get_evergreen_refill_plan":
229
- result = await getEvergreenRefillPlan(args);
230
+ result = await getRefillPlanV2(args);
230
231
  break;
231
232
  case "get_refill_target_plan":
232
233
  result = await getRefillTargetPlan(args);
@@ -237,8 +238,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
237
238
  case "refill_sends":
238
239
  result = await executeRefillSendsCommand(args);
239
240
  break;
241
+ case "refill_sends_v2":
240
242
  case "refill_sends_evergreen":
241
- result = refillSendsEvergreenCommand(args);
243
+ result = refillSendsV2Command(args);
242
244
  break;
243
245
  case "setup_evergreen_campaigns":
244
246
  result = await setupEvergreenCampaigns(args);
@@ -1,12 +1,13 @@
1
- type GetEvergreenRefillPlanInput = {
1
+ type GetRefillPlanV2Input = {
2
2
  workspaceId?: string;
3
+ intent?: "auto" | "evergreen" | "plain" | "active";
3
4
  senderIds?: string[];
4
5
  runState?: Record<string, unknown>;
5
6
  journal?: boolean;
6
7
  journalNote?: string;
7
8
  };
8
9
  export declare function sanitizeEvergreenRefillPlanResult(value: unknown): Record<string, unknown>;
9
- export declare const evergreenRefillPlanToolDefinitions: {
10
+ export declare const refillPlanV2ToolDefinitions: {
10
11
  name: string;
11
12
  description: string;
12
13
  inputSchema: {
@@ -26,6 +27,11 @@ export declare const evergreenRefillPlanToolDefinitions: {
26
27
  type: string;
27
28
  description: string;
28
29
  };
30
+ intent: {
31
+ type: string;
32
+ enum: string[];
33
+ description: string;
34
+ };
29
35
  journal: {
30
36
  type: string;
31
37
  description: string;
@@ -39,11 +45,25 @@ export declare const evergreenRefillPlanToolDefinitions: {
39
45
  additionalProperties: boolean;
40
46
  };
41
47
  }[];
42
- export declare function getEvergreenRefillPlan(input: GetEvergreenRefillPlanInput): Promise<{
48
+ export declare function getRefillPlanV2(input: GetRefillPlanV2Input): Promise<{
49
+ readOnly: boolean;
50
+ blocker: string;
51
+ workspaceId: string;
52
+ guidance: string;
53
+ warnings: string[];
54
+ journalPath: string | null;
55
+ text: string;
56
+ workspaceResolution: string;
57
+ } | {
43
58
  warnings: any[];
44
59
  journalPath: string | null;
45
60
  text: string;
46
61
  workspaceId: string;
47
62
  workspaceResolution: string;
63
+ readOnly?: undefined;
64
+ blocker?: undefined;
65
+ guidance?: undefined;
48
66
  }>;
67
+ /** @deprecated Use getRefillPlanV2. */
68
+ export declare const getEvergreenRefillPlan: typeof getRefillPlanV2;
49
69
  export {};
@@ -1,5 +1,5 @@
1
1
  import * as path from "node:path";
2
- import { getApi } from "../api.js";
2
+ import { getApi, SellableApiError } from "../api.js";
3
3
  import { appendIndexLine, appendJournalEvent, createRunJournal, renderBootstrapSection, renderPlanSection, renderTerminalSection, } from "../refill-journal.js";
4
4
  import { readRefillWorkspaceState } from "../refill-local-state.js";
5
5
  import { normalizeExplicitWorkspaceId, workspaceRequestOptions, } from "./workspace-context.js";
@@ -45,7 +45,7 @@ function buildRunStateFromLocalHints(workspaceId) {
45
45
  passRates: state?.passRates ?? [],
46
46
  };
47
47
  }
48
- async function postEvergreenRefillPlan(body, workspaceId) {
48
+ async function postRefillPlanV2(body, workspaceId) {
49
49
  const api = getApi();
50
50
  const requestOptions = workspaceRequestOptions(workspaceId);
51
51
  return requestOptions
@@ -75,7 +75,7 @@ function writeDryRunJournal(params) {
75
75
  ? params.result.bootstrap
76
76
  : {};
77
77
  appendJournalEvent(created.filePath, renderBootstrapSection({
78
- summary: "Evergreen refill dry-run bootstrap",
78
+ summary: "Refill v2 dry-run bootstrap across managed waterfall, dashboard evergreen, and active campaign lanes",
79
79
  senderSummary: JSON.stringify(bootstrap.senders ?? []),
80
80
  laneSummary: JSON.stringify(bootstrap.laneOrder ?? []),
81
81
  targetSummary: JSON.stringify(bootstrap.target ?? []),
@@ -113,14 +113,48 @@ function writeDryRunJournal(params) {
113
113
  fileName: path.basename(created.filePath),
114
114
  workspaceId: params.workspaceId,
115
115
  dryRun: true,
116
- summary: "evergreen refill dry-run",
116
+ summary: "refill v2 dry-run",
117
117
  });
118
118
  return created.filePath;
119
119
  }
120
- export const evergreenRefillPlanToolDefinitions = [
120
+ function writeWorkspaceAccessJournal(params) {
121
+ const created = createRunJournal({
122
+ workspaceId: params.workspaceId,
123
+ dryRun: true,
124
+ });
125
+ appendJournalEvent(created.filePath, renderBootstrapSection({
126
+ summary: "Refill v2 dry-run bootstrap stopped at workspace access",
127
+ senderSummary: "[]",
128
+ laneSummary: "[]",
129
+ targetSummary: `workspaceId=${params.workspaceId}`,
130
+ creditSummary: "[]",
131
+ }));
132
+ appendJournalEvent(created.filePath, renderPlanSection({
133
+ chosenSummary: "workspace_access blocker",
134
+ itinerarySummaries: ["No workspace campaign state read"],
135
+ fallbackSummary: "terminal:workspace_access",
136
+ }));
137
+ appendJournalEvent(created.filePath, renderTerminalSection({
138
+ summary: `blocker=workspace_access workspaceId=${params.workspaceId} ${params.guidance}`,
139
+ }));
140
+ appendIndexLine({
141
+ runId: created.runId,
142
+ fileName: path.basename(created.filePath),
143
+ workspaceId: params.workspaceId,
144
+ dryRun: true,
145
+ summary: "refill v2 dry-run workspace_access blocker",
146
+ });
147
+ return created.filePath;
148
+ }
149
+ function isWorkspaceAccessError(error) {
150
+ return (error instanceof SellableApiError &&
151
+ error.status === 403 &&
152
+ error.body.includes("No access to workspace"));
153
+ }
154
+ export const refillPlanV2ToolDefinitions = [
121
155
  {
122
- name: "get_evergreen_refill_plan",
123
- description: "Read-only evergreen refill dry-run planner. It performs no mutations, does not schedule, send, approve, prepare, or refresh credits, and writes a local dry-run journal file unless journal:false is passed.",
156
+ name: "get_refill_plan_v2",
157
+ description: "Read-only refill sends v2 dry-run planner across managed waterfall, dashboard evergreen, and active campaign lanes. It performs no mutations, does not schedule, send, approve, prepare, or refresh credits, and writes a local dry-run journal file unless journal:false is passed.",
124
158
  inputSchema: {
125
159
  type: "object",
126
160
  properties: {
@@ -136,6 +170,11 @@ export const evergreenRefillPlanToolDefinitions = [
136
170
  type: "object",
137
171
  description: "Optional synthetic v1 run state. When provided, replaces local lane-memory hints.",
138
172
  },
173
+ intent: {
174
+ type: "string",
175
+ enum: ["auto", "evergreen", "plain", "active"],
176
+ description: 'Planner intent. Defaults to "auto" for refill-sends-v2.',
177
+ },
139
178
  journal: {
140
179
  type: "boolean",
141
180
  description: "Set false to skip the local dry-run journal write.",
@@ -150,19 +189,55 @@ export const evergreenRefillPlanToolDefinitions = [
150
189
  },
151
190
  },
152
191
  ];
153
- export async function getEvergreenRefillPlan(input) {
192
+ export async function getRefillPlanV2(input) {
154
193
  const workspaceId = normalizeExplicitWorkspaceId(input.workspaceId);
155
194
  if (!workspaceId) {
156
- throw new Error("workspaceId is required for get_evergreen_refill_plan.");
195
+ throw new Error("workspaceId is required for get_refill_plan_v2.");
157
196
  }
158
197
  const runState = input.runState !== undefined
159
198
  ? input.runState
160
199
  : buildRunStateFromLocalHints(workspaceId);
161
- const raw = await postEvergreenRefillPlan({
162
- workspaceId,
163
- senderIds: input.senderIds,
164
- runState,
165
- }, workspaceId);
200
+ let raw;
201
+ try {
202
+ raw = await postRefillPlanV2({
203
+ workspaceId,
204
+ intent: input.intent ?? "auto",
205
+ senderIds: input.senderIds,
206
+ runState,
207
+ }, workspaceId);
208
+ }
209
+ catch (error) {
210
+ if (!isWorkspaceAccessError(error))
211
+ throw error;
212
+ const guidance = error instanceof SellableApiError && error.guidance
213
+ ? error.guidance
214
+ : "The authenticated user is not a member of this workspace. Confirm the workspaceId or ask a workspace admin to add the user; re-login will not help.";
215
+ const warnings = [];
216
+ let journalPath = null;
217
+ if (input.journal !== false) {
218
+ try {
219
+ journalPath = writeWorkspaceAccessJournal({ workspaceId, guidance });
220
+ }
221
+ catch {
222
+ warnings.push("journalWriteFailed");
223
+ }
224
+ }
225
+ return {
226
+ readOnly: true,
227
+ blocker: "workspace_access",
228
+ workspaceId,
229
+ guidance,
230
+ warnings,
231
+ journalPath,
232
+ text: [
233
+ "Refill sends v2 dry-run blocked: workspace_access",
234
+ `Workspace: ${workspaceId}`,
235
+ guidance,
236
+ journalPath ? `Journal: ${journalPath}` : "Journal: not written",
237
+ ].join("\n"),
238
+ workspaceResolution: "explicit",
239
+ };
240
+ }
166
241
  const sanitized = sanitizeEvergreenRefillPlanResult(raw);
167
242
  const warnings = Array.isArray(sanitized.warnings)
168
243
  ? [...sanitized.warnings]
@@ -181,7 +256,7 @@ export async function getEvergreenRefillPlan(input) {
181
256
  }
182
257
  }
183
258
  const summary = [
184
- "Evergreen refill dry-run plan:",
259
+ "Refill sends v2 dry-run plan:",
185
260
  ...planSummaryLines(sanitized),
186
261
  journalPath ? `Journal: ${journalPath}` : "Journal: not written",
187
262
  ].join("\n");
@@ -194,3 +269,5 @@ export async function getEvergreenRefillPlan(input) {
194
269
  workspaceResolution: "explicit",
195
270
  };
196
271
  }
272
+ /** @deprecated Use getRefillPlanV2. */
273
+ export const getEvergreenRefillPlan = getRefillPlanV2;
@@ -137,7 +137,8 @@ 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-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends", "refill-sends-evergreen", "refill-sends-evergreen-workflow", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
140
+ export declare const DEPRECATED_SUBSKILL_PROMPT_REPLACEMENTS: Record<string, string>;
141
+ 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-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends", "refill-sends-evergreen", "refill-sends-evergreen-workflow", "refill-sends-v2", "refill-sends-v2-workflow", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
141
142
  export declare const promptToolDefinitions: ({
142
143
  name: string;
143
144
  description: string;
@@ -181,7 +182,7 @@ export declare const promptToolDefinitions: ({
181
182
  properties: {
182
183
  subskillName: {
183
184
  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-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends", "refill-sends-evergreen", "refill-sends-evergreen-workflow", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
185
+ 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-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends", "refill-sends-evergreen", "refill-sends-evergreen-workflow", "refill-sends-v2", "refill-sends-v2-workflow", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
185
186
  description: string;
186
187
  };
187
188
  offset: {
@@ -216,7 +217,7 @@ export declare const promptToolDefinitions: ({
216
217
  properties: {
217
218
  subskillName: {
218
219
  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-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends", "refill-sends-evergreen", "refill-sends-evergreen-workflow", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
220
+ 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-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends", "refill-sends-evergreen", "refill-sends-evergreen-workflow", "refill-sends-v2", "refill-sends-v2-workflow", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
220
221
  description: string;
221
222
  };
222
223
  assetPath: {
@@ -13,8 +13,10 @@ import { markCreateCampaignPromptLoaded, markResearchPromptLoaded, markSenderRes
13
13
  // ~3s.
14
14
  export const DEFAULT_SUBSKILL_PROMPT_CHUNK_CHARS = 48_000;
15
15
  export const MAX_SUBSKILL_PROMPT_CHUNK_CHARS = 48_000;
16
- const DEPRECATED_SUBSKILL_PROMPT_REPLACEMENTS = {
16
+ export const DEPRECATED_SUBSKILL_PROMPT_REPLACEMENTS = {
17
17
  "generate-messages-compact": "generate-messages",
18
+ "refill-sends-evergreen": "refill-sends-v2",
19
+ "refill-sends-evergreen-workflow": "refill-sends-v2-workflow",
18
20
  };
19
21
  export const ALLOWED_SUBSKILL_PROMPT_NAMES = [
20
22
  "building-gtm-tables",
@@ -40,6 +42,8 @@ export const ALLOWED_SUBSKILL_PROMPT_NAMES = [
40
42
  "refill-sends",
41
43
  "refill-sends-evergreen",
42
44
  "refill-sends-evergreen-workflow",
45
+ "refill-sends-v2",
46
+ "refill-sends-v2-workflow",
43
47
  "refill-sends-workflow",
44
48
  "research",
45
49
  "research-prospect",
@@ -0,0 +1,28 @@
1
+ type RefillSendsV2Input = {
2
+ workspaceId?: string;
3
+ };
4
+ export declare const refillSendsV2ToolDefinitions: {
5
+ name: string;
6
+ description: string;
7
+ inputSchema: {
8
+ type: string;
9
+ properties: {
10
+ workspaceId: {
11
+ type: string;
12
+ description: string;
13
+ };
14
+ };
15
+ required: string[];
16
+ additionalProperties: boolean;
17
+ };
18
+ }[];
19
+ export declare function refillSendsV2Command(input: RefillSendsV2Input): {
20
+ readOnly: boolean;
21
+ workspaceId: string | null;
22
+ firstOperationalSteps: string[];
23
+ approvalContract: string;
24
+ forbiddenActions: string[];
25
+ fillWindow: string;
26
+ hostExamples: string[];
27
+ };
28
+ export {};
@@ -0,0 +1,49 @@
1
+ export const refillSendsV2ToolDefinitions = [
2
+ {
3
+ name: "refill_sends_v2",
4
+ description: "Read-only refill sends v2 command contract. It performs no mutations and tells the operator to call get_refill_plan_v2 for a dry-run packet and journal across managed waterfall, dashboard evergreen, and active campaign lanes.",
5
+ inputSchema: {
6
+ type: "object",
7
+ properties: {
8
+ workspaceId: {
9
+ type: "string",
10
+ description: "Explicit request-scoped workspace id.",
11
+ },
12
+ },
13
+ required: ["workspaceId"],
14
+ additionalProperties: false,
15
+ },
16
+ },
17
+ ];
18
+ export function refillSendsV2Command(input) {
19
+ return {
20
+ readOnly: true,
21
+ workspaceId: input.workspaceId ?? null,
22
+ firstOperationalSteps: [
23
+ "Call get_refill_plan_v2 first with the explicit workspaceId.",
24
+ "Read the returned packet, globalActionQueue, per-sender plans, laneOrder source labels, laneChain values, and itinerary before taking any action.",
25
+ "Confirm which lane source was selected for each sender: managed_waterfall, dashboard_evergreen, or active_campaign.",
26
+ "Review the refill v2 dry-run journal file path returned by get_refill_plan_v2.",
27
+ "If the packet reports no_refillable_campaigns or workspace_access, stop and report that blocker instead of mutating.",
28
+ "This command is PLAN-ONLY; execution arrives in Phase 86.",
29
+ ],
30
+ approvalContract: "Nothing is approved or executable in Phase 87. The refill_sends_v2 command is read-only; Phase 86 introduces execution approval.",
31
+ forbiddenActions: [
32
+ "Do not schedule sends.",
33
+ "Do not send messages.",
34
+ "Do not approve messages.",
35
+ "Do not prepare messages.",
36
+ "Do not start or launch campaigns.",
37
+ "Do not create campaigns.",
38
+ "Do not switch providers or source families.",
39
+ "Do not lower paid InMail thresholds.",
40
+ "Do not refresh paid InMail credits.",
41
+ "Do not write scheduler fields.",
42
+ ],
43
+ fillWindow: "Use only the target window and caps returned by get_refill_plan_v2.",
44
+ hostExamples: [
45
+ "refill_sends_v2({ workspaceId })",
46
+ "get_refill_plan_v2({ workspaceId })",
47
+ ],
48
+ };
49
+ }
@@ -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-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends", "refill-sends-evergreen", "refill-sends-evergreen-workflow", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "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-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends", "refill-sends-evergreen", "refill-sends-evergreen-workflow", "refill-sends-v2", "refill-sends-v2-workflow", "refill-sends-workflow", "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-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends", "refill-sends-evergreen", "refill-sends-evergreen-workflow", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "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-evergreen-campaigns", "create-post", "create-rubric", "engage", "enrich-prospects", "fill-send-horizon", "find-leads", "foundation", "generate-messages", "interview", "load-voice", "refresh-sender-engagement", "refill-sends", "refill-sends-evergreen", "refill-sends-evergreen-workflow", "refill-sends-v2", "refill-sends-v2-workflow", "refill-sends-workflow", "research", "research-prospect", "research-sender", "weekly-campaign-summary", "workflow-sequences"];
275
275
  description: string;
276
276
  };
277
277
  assetPath: {
@@ -585,20 +585,6 @@ export declare const allTools: ({
585
585
  additionalProperties: boolean;
586
586
  required?: undefined;
587
587
  };
588
- } | {
589
- name: string;
590
- description: string;
591
- inputSchema: {
592
- type: string;
593
- properties: {
594
- workspaceId: {
595
- type: string;
596
- description: string;
597
- };
598
- };
599
- required: string[];
600
- additionalProperties: boolean;
601
- };
602
588
  } | {
603
589
  name: string;
604
590
  description: string;
@@ -7197,6 +7183,20 @@ export declare const allTools: ({
7197
7183
  };
7198
7184
  required: string[];
7199
7185
  };
7186
+ } | {
7187
+ name: string;
7188
+ description: string;
7189
+ inputSchema: {
7190
+ type: string;
7191
+ properties: {
7192
+ workspaceId: {
7193
+ type: string;
7194
+ description: string;
7195
+ };
7196
+ };
7197
+ required: string[];
7198
+ additionalProperties: boolean;
7199
+ };
7200
7200
  } | {
7201
7201
  name: string;
7202
7202
  description: string;
@@ -5,8 +5,8 @@ import { campaignAbTestToolDefinitions } from "./campaign-ab-test.js";
5
5
  import { campaignFillRoutingToolDefinitions } from "./campaign-fill-routing.js";
6
6
  import { campaignHorizonFillToolDefinitions } from "./campaign-horizon-fill.js";
7
7
  import { campaignMessagePreparationToolDefinitions } from "./campaign-message-preparation.js";
8
- import { campaignRefillStateToolDefinitions } from "./campaign-refill-state.js";
9
8
  import { campaignProcessingToolDefinitions } from "./campaign-processing.js";
9
+ import { campaignRefillStateToolDefinitions } from "./campaign-refill-state.js";
10
10
  import { campaignToolDefinitions } from "./campaigns.js";
11
11
  import { cellToolDefinitions } from "./cells.js";
12
12
  import { startCliLoginToolDef, waitForCliLoginToolDef } from "./cli-login.js";
@@ -23,6 +23,7 @@ import { engageDiscoveryToolDefinitions } from "./engage-discovery.js";
23
23
  import { engageMemoryToolDefinitions } from "./engage-memory.js";
24
24
  import { engageStateToolDefinitions } from "./engage-state.js";
25
25
  import { enrichmentToolDefinitions } from "./enrichment.js";
26
+ import { refillPlanV2ToolDefinitions } from "./evergreen-refill-plan.js";
26
27
  import { frameworkToolDefinitions } from "./framework.js";
27
28
  import { harvestJobToolDefinitions } from "./harvest-jobs.js";
28
29
  import { inboxToolDefinitions } from "./inbox.js";
@@ -33,10 +34,9 @@ import { onDemandToolDefinitions } from "./one-off.js";
33
34
  import { processingToolDefinitions } from "./processing.js";
34
35
  import { promptToolDefinitions } from "./prompts.js";
35
36
  import { readinessToolDefinitions } from "./readiness.js";
36
- import { evergreenRefillPlanToolDefinitions } from "./evergreen-refill-plan.js";
37
- import { refillSendsEvergreenToolDefinitions } from "./refill-sends-evergreen.js";
38
- import { refillTargetPlanToolDefinitions } from "./refill-target-plan.js";
37
+ import { refillSendsV2ToolDefinitions } from "./refill-sends-v2.js";
39
38
  import { refillSendsToolDefinitions } from "./refill-sends.js";
39
+ import { refillTargetPlanToolDefinitions } from "./refill-target-plan.js";
40
40
  import { rowToolDefinitions } from "./rows.js";
41
41
  import { rubricToolDefinitions } from "./rubrics.js";
42
42
  import { schedulerFillCapacityToolDefinitions } from "./scheduler-fill-capacity.js";
@@ -54,11 +54,11 @@ export const allTools = [
54
54
  ...campaignAbTestToolDefinitions,
55
55
  ...campaignFillRoutingToolDefinitions,
56
56
  ...campaignRefillStateToolDefinitions,
57
- ...evergreenRefillPlanToolDefinitions,
57
+ ...refillPlanV2ToolDefinitions,
58
58
  ...refillTargetPlanToolDefinitions,
59
59
  ...schedulerFillCapacityToolDefinitions,
60
60
  ...refillSendsToolDefinitions,
61
- ...refillSendsEvergreenToolDefinitions,
61
+ ...refillSendsV2ToolDefinitions,
62
62
  ...setupEvergreenCampaignsToolDefinitions,
63
63
  ...campaignHorizonFillToolDefinitions,
64
64
  ...campaignMessagePreparationToolDefinitions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.512",
3
+ "version": "0.1.513",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -1,84 +1,19 @@
1
1
  ---
2
2
  name: refill-sends-evergreen
3
- description: Plan evergreen waterfall send refill work through the Phase 85 dry-run workflow.
3
+ description: Deprecated alias for refill-sends-v2.
4
4
  visibility: public
5
5
  allowed-tools:
6
- - mcp__sellable__refill_sends_evergreen
7
- - mcp__sellable__get_evergreen_refill_plan
8
6
  - mcp__sellable__get_subskill_prompt
9
- - mcp__sellable__get_subskill_asset
10
- - mcp__sellable__get_auth_status
11
- - mcp__sellable__get_active_workspace
12
- - mcp__sellable__list_workspaces
13
- - mcp__sellable__get_workspace
14
7
  ---
15
8
 
16
9
  # Refill Sends Evergreen
17
10
 
18
- Use this public command wrapper for evergreen waterfall refill requests such as
19
- "refill evergreen", "fill evergreen senders", "load evergreen lanes", or
20
- "plan evergreen refill".
11
+ Superseded by refill-sends-v2. The prompt name now redirects through
12
+ `DEPRECATED_SUBSKILL_PROMPT_REPLACEMENTS`; do not call this deprecated prompt
13
+ directly.
21
14
 
22
- Host command names:
23
-
24
- - Claude Code: `/sellable:refill-sends-evergreen`
25
- - Codex: `$sellable:refill-sends-evergreen`
26
-
27
- Phase 85 is read-only, dry-run, zero mutations. It plans the deterministic
28
- waterfall-ladder refill packet and writes a local dry-run journal, but it does
29
- not prepare messages, approve messages, start campaigns, schedule sends, send
30
- messages, refresh paid InMail credit facts, create campaigns, or change source
31
- configuration. Execution ships in the follow-up phase.
32
-
33
- ## Entry
34
-
35
- Resolve the explicit `workspaceId` from the request, automation config, or
36
- active workspace readback. Scheduled or autonomous usage must carry
37
- `workspaceId` on every tool call. If the workspace is missing or ambiguous, stop
38
- with `WORKSPACE_REQUIRED`; do not switch the shared active workspace.
39
-
40
- Start with the command contract:
15
+ Use `refill-sends-v2` instead:
41
16
 
42
17
  ```text
43
- refill_sends_evergreen({ workspaceId })
18
+ get_subskill_prompt({ subskillName: "refill-sends-v2" })
44
19
  ```
45
-
46
- Then load the internal workflow prompt and flow asset:
47
-
48
- ```text
49
- get_subskill_prompt({ subskillName: "refill-sends-evergreen-workflow" })
50
- get_subskill_asset({ subskillName: "refill-sends-evergreen-workflow", assetPath: "core/flow.v1.json" })
51
- ```
52
-
53
- Continue both loads until `hasMore:false`; parse the flow JSON and verify
54
- `workflow:"refill-sends-evergreen-workflow"` with a `v1` version before the
55
- planner call.
56
-
57
- Call the dry-run planner with the explicit workspace id:
58
-
59
- ```text
60
- get_evergreen_refill_plan({ workspaceId, senderIds?, runState?, journal?, journalNote? })
61
- ```
62
-
63
- Use `senderIds` only when the user scoped the request to exact senders. Use
64
- `runState` only for an explicit what-if dry run; otherwise let the MCP read
65
- local lane memory hints. Leave `journal` enabled unless the user specifically
66
- asked for no local journal.
67
-
68
- ## Report
69
-
70
- Review the returned packet before giving a recommendation:
71
-
72
- - `planRevision` starts with `pr1:`.
73
- - `stateRevision` identifies the current readback.
74
- - `packet` is the operator-facing facts receipt.
75
- - `plans[]` contains per-sender lane decisions and itinerary details.
76
- - `globalActionQueue[]` is a dry-run sequence only in Phase 85.
77
- - `evergreen.enumeratedRungs` and each action's `evergreenRung` map to the
78
- locked ladder from the workflow asset.
79
- - `journalPath` points to the dry-run markdown journal written by the MCP.
80
- - `sideEffects` must be all false.
81
-
82
- Report campaign names and sender names first, ids second. Include the chosen
83
- rung, the itinerary, the plan revision, the journal path, and any blockers or
84
- warnings. Stop after the report; do not execute the action queue in Phase 85.
@@ -1,107 +1,20 @@
1
1
  ---
2
2
  name: refill-sends-evergreen-workflow
3
- description: Internal read-only workflow for evergreen waterfall refill dry-run planning.
3
+ description: Deprecated alias for refill-sends-v2-workflow.
4
4
  visibility: internal
5
5
  allowed-tools:
6
- - mcp__sellable__refill_sends_evergreen
7
- - mcp__sellable__get_evergreen_refill_plan
8
6
  - mcp__sellable__get_subskill_prompt
9
- - mcp__sellable__get_subskill_asset
10
- - mcp__sellable__get_auth_status
11
- - mcp__sellable__get_active_workspace
12
- - mcp__sellable__list_workspaces
13
- - mcp__sellable__get_workspace
14
7
  ---
15
8
 
16
9
  # Refill Sends Evergreen Workflow
17
10
 
18
- This internal workflow is the Phase 85 plan surface for evergreen waterfall
19
- refill. It is read-only, dry-run, zero mutations. The workflow has three gates:
20
- bootstrap, plan, and report.
11
+ Superseded by refill-sends-v2-workflow. The prompt name now redirects through
12
+ `DEPRECATED_SUBSKILL_PROMPT_REPLACEMENTS`; do not call this deprecated prompt or
13
+ its old flow asset directly.
21
14
 
22
- Runtime flow asset: after loading this prompt, load
23
- `get_subskill_asset({ subskillName: "refill-sends-evergreen-workflow", assetPath: "core/flow.v1.json" })`
24
- through MCP, continue chunks until `hasMore:false`, parse the JSON, and verify
25
- `workflow:"refill-sends-evergreen-workflow"` with a `v1` version before any
26
- planner call. If the asset cannot load or parse, stop with
27
- `blocked:evergreen_refill_workflow_asset_unavailable`; do not emulate it from
28
- local files or memory.
15
+ Use `refill-sends-v2-workflow` instead:
29
16
 
30
- ## G0 Bootstrap Facts
31
-
32
- Resolve the request-scoped `workspaceId` using read-only auth and workspace
33
- tools. Scheduled or autonomous runs must not rely on implicit workspace state.
34
- Call `refill_sends_evergreen({ workspaceId })` first to receive the command
35
- contract, then call `get_evergreen_refill_plan({ workspaceId })` for the dry-run
36
- packet.
37
-
38
- Optional inputs:
39
-
40
- - `senderIds`: exact sender scope when the user named senders.
41
- - `runState`: synthetic v1 lane memory for what-if dry runs. Use it only when
42
- the user intentionally wants a hypothetical cursor, pin, or cooldown state.
43
- - `journal:false`: skip the local journal only when explicitly requested.
44
- - `journalNote`: append operator context to the dry-run terminal section.
45
-
46
- ## G1 Evergreen Ladder
47
-
48
- The planner chooses from this locked rung order:
49
-
50
- 1. `start_campaign`: a paused selected lane has scheduler-ready supply but must
51
- be live before the scheduler can pick it up.
52
- 2. `approve_messages`: generated rows are ready for a bounded approval step.
53
- 3. `wait_for_active_work`: enrichment, generation, import, or preparation is
54
- already active, so the next honest action is to wait for that work to finish.
55
- 4. `enrich_more`: exact-set enrichment can close the current ready gap.
56
- 5. `reconcile_source_copy`: same-source rows exist and can be copied without
57
- changing source family or source fingerprint.
58
- 6. `add_leads_same_source`: the same source path can add bounded new supply.
59
- 7. `paid_lane_fallback`: paid InMail is blocked or below threshold, so the same
60
- waterfall can fall back to an existing supported lane.
61
- 8. `next_campaign`: the current lane is exhausted, cooling down, pinned away, or
62
- unsafe, and the next surviving campaign lane should be inspected.
63
- 9. `wait_for_scheduler`: ready or projected supply covers the target, and only
64
- scheduler pickup remains.
65
- 10. `done`: the sender or lane is complete for the selected target window, or a
66
- scheduler cap makes additional preparation unnecessary.
67
-
68
- Forward-only lane rule: a lane can move to a later rung or a later surviving
69
- campaign, but the dry-run packet must not jump backward to invent work that the
70
- facts do not support. Pinned-campaign rule: a pinned campaign stays selected
71
- until the planner proves a blocker, cooldown, exhaustion, or safer next lane.
72
- Capped-is-complete rule: when scheduler capacity is lower than the requested
73
- target and ready/projected coverage satisfies that cap, report `done` with the
74
- cap reason. Honest-itinerary rule: show what was checked, what was skipped, and
75
- why; never hide uncertainty behind a confident source recommendation.
76
-
77
- Guardrails inherited from the Phase 83 evergreen workflow: no campaign creation,
78
- no provider-family switch, no threshold lowering, no scheduler writes, no
79
- launch/send/archive/delete, no brief/filter/message/sequence/sender mutation,
80
- no message preparation, no message approval, no paid InMail credit refresh, no
81
- source mutation, no row queueing, and no campaign status change.
82
-
83
- ## Journal
84
-
85
- `get_evergreen_refill_plan` writes a local dry-run journal unless
86
- `journal:false` is passed. Read the returned `journalPath` from the tool result
87
- and include it in the report. The journal contains bootstrap, plan, and terminal
88
- sections plus an index line under the run journal directory. If the tool returns
89
- `journalPath:null` with a `journalWriteFailed` warning, report the warning and
90
- continue with the dry-run packet; do not retry by writing local files yourself.
91
-
92
- ## Report Contract
93
-
94
- Completion for Phase 85 means packet reviewed and journal written. Merely
95
- calling `get_evergreen_refill_plan` is not completion proof.
96
-
97
- Report these facts:
98
-
99
- - workspace id and selected sender scope;
100
- - plan revision and state revision;
101
- - selected campaign and lane per sender;
102
- - chosen rung and dry-run action queue;
103
- - itinerary, skipped lanes, blockers, cooldowns, and warnings;
104
- - journal path;
105
- - side effects proof, which must show all false values.
106
-
107
- Stop after the report. The Phase 85 workflow never executes the action queue.
17
+ ```text
18
+ get_subskill_prompt({ subskillName: "refill-sends-v2-workflow" })
19
+ get_subskill_asset({ subskillName: "refill-sends-v2-workflow", assetPath: "core/flow.v1.json" })
20
+ ```
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: refill-sends-v2
3
+ description: Plan refill sends v2 work through the read-only three-lane dry-run planner.
4
+ visibility: public
5
+ allowed-tools:
6
+ - mcp__sellable__refill_sends_v2
7
+ - mcp__sellable__get_refill_plan_v2
8
+ - mcp__sellable__get_subskill_prompt
9
+ - mcp__sellable__get_subskill_asset
10
+ - mcp__sellable__get_auth_status
11
+ - mcp__sellable__get_active_workspace
12
+ - mcp__sellable__list_workspaces
13
+ - mcp__sellable__get_workspace
14
+ ---
15
+
16
+ # Refill Sends V2
17
+
18
+ Use this public command wrapper for refill planning requests such as "refill
19
+ sends", "fill evergreen senders", "load everyone up", "plan Damiano", or "show a
20
+ dry-run for this workspace".
21
+
22
+ Host command names:
23
+
24
+ - Claude Code: `/sellable:refill-sends-v2`
25
+ - Codex: `$sellable:refill-sends-v2`
26
+
27
+ This is plan-only, read-only, dry-run, zero mutations. It creates no campaigns,
28
+ does not prepare or approve messages, does not start campaigns, does not
29
+ schedule or send messages, does not refresh paid InMail credit facts, and does
30
+ not change source configuration. Execution remains in the Phase 86 workflow.
31
+
32
+ ## Entry
33
+
34
+ Resolve the explicit `workspaceId` from the request, automation config, or
35
+ active workspace readback. Scheduled or autonomous usage must carry
36
+ `workspaceId` on every tool call. If the workspace is missing or ambiguous, stop
37
+ with `WORKSPACE_REQUIRED`; do not switch the shared active workspace.
38
+
39
+ Start with the command contract:
40
+
41
+ ```text
42
+ refill_sends_v2({ workspaceId })
43
+ ```
44
+
45
+ Then load the internal workflow prompt and flow asset:
46
+
47
+ ```text
48
+ get_subskill_prompt({ subskillName: "refill-sends-v2-workflow" })
49
+ get_subskill_asset({ subskillName: "refill-sends-v2-workflow", assetPath: "core/flow.v1.json" })
50
+ ```
51
+
52
+ Continue both loads until `hasMore:false`; parse the flow JSON and verify
53
+ `workflow:"refill-sends-v2-workflow"` with a `v1` version before the planner
54
+ call.
55
+
56
+ Call the dry-run planner with the explicit workspace id:
57
+
58
+ ```text
59
+ get_refill_plan_v2({ workspaceId, intent:"auto", senderIds?, runState?, journal?, journalNote? })
60
+ ```
61
+
62
+ The default `intent:"auto"` checks the three lane-source families in order:
63
+
64
+ - `managed_waterfall` for product-managed evergreen waterfall lanes.
65
+ - `dashboard_evergreen` for dashboard-visible evergreen campaigns.
66
+ - `active_campaign` for regular active campaigns that should refill through a
67
+ deterministic lane chain.
68
+
69
+ Use `senderIds` only when the user scoped the request to exact senders. Use
70
+ `runState` only for an explicit what-if dry run; otherwise let the MCP read
71
+ local lane memory hints. Leave `journal` enabled unless the user specifically
72
+ asked for no local journal.
73
+
74
+ ## Report
75
+
76
+ Review the returned packet before giving a recommendation:
77
+
78
+ - `planRevision` starts with `pr1:`.
79
+ - `stateRevision` identifies the current readback.
80
+ - `packet` is the operator-facing facts receipt.
81
+ - `plans[]` contains per-sender lane decisions and itinerary details.
82
+ - `globalActionQueue[]` is a dry-run sequence only.
83
+ - `evergreen.laneOrder[].source` uses `managed_waterfall`,
84
+ `dashboard_evergreen`, or `active_campaign`.
85
+ - `evergreen.senderLaneSelections[].laneChain` records the ordered lane chain
86
+ when a regular active campaign chain is selected.
87
+ - Terminals can include `done` or `no_refillable_campaigns`.
88
+ - A membership 403 must return the structured `workspace_access` blocker; report
89
+ it as a read-only blocker, not a login retry.
90
+ - `journalPath` points to the dry-run markdown journal written by the MCP.
91
+ - `sideEffects` must be all false.
92
+
93
+ Report campaign names and sender names first, ids second. Include the lane
94
+ source, lane chain when present, chosen rung, itinerary, plan revision, journal
95
+ path, and any blockers or warnings. Stop after the report; do not execute the
96
+ action queue.
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: refill-sends-v2-workflow
3
+ description: Internal read-only workflow for refill sends v2 dry-run planning.
4
+ visibility: internal
5
+ allowed-tools:
6
+ - mcp__sellable__refill_sends_v2
7
+ - mcp__sellable__get_refill_plan_v2
8
+ - mcp__sellable__get_subskill_prompt
9
+ - mcp__sellable__get_subskill_asset
10
+ - mcp__sellable__get_auth_status
11
+ - mcp__sellable__get_active_workspace
12
+ - mcp__sellable__list_workspaces
13
+ - mcp__sellable__get_workspace
14
+ ---
15
+
16
+ # Refill Sends V2 Workflow
17
+
18
+ This internal workflow is the read-only, dry-run, zero mutations plan surface
19
+ for refill sends v2. The workflow has three gates: bootstrap, plan, and report.
20
+ It covers product-managed evergreen workspaces, dashboard evergreen workspaces,
21
+ and non-evergreen active campaign workspaces without creating new campaigns.
22
+
23
+ Runtime flow asset: after loading this prompt, load
24
+ `get_subskill_asset({ subskillName: "refill-sends-v2-workflow", assetPath: "core/flow.v1.json" })`
25
+ through MCP, continue chunks until `hasMore:false`, parse the JSON, and verify
26
+ `workflow:"refill-sends-v2-workflow"` with a `v1` version before any planner
27
+ call. If the asset cannot load or parse, stop with
28
+ `blocked:refill_sends_v2_workflow_asset_unavailable`; do not emulate it from
29
+ local files or memory.
30
+
31
+ ## G0 Bootstrap Facts
32
+
33
+ Resolve the request-scoped `workspaceId` using read-only auth and workspace
34
+ tools. Scheduled or autonomous runs must not rely on implicit workspace state.
35
+ Call `refill_sends_v2({ workspaceId })` first to receive the command contract,
36
+ then call `get_refill_plan_v2({ workspaceId, intent:"auto" })` for the dry-run
37
+ packet.
38
+
39
+ Optional inputs:
40
+
41
+ - `senderIds`: exact sender scope when the user named senders.
42
+ - `intent`: defaults to `auto`. Use explicit `evergreen`, `plain`, or `active`
43
+ only for a what-if comparison.
44
+ - `runState`: synthetic v1 lane memory for what-if dry runs. Use it only when
45
+ the user intentionally wants a hypothetical cursor, pin, cooldown state, or
46
+ laneChain replay.
47
+ - `journal:false`: skip the local journal only when explicitly requested.
48
+ - `journalNote`: append operator context to the dry-run terminal section.
49
+
50
+ ## G1 Lane Sources
51
+
52
+ The planner reports the lane source for every selected lane:
53
+
54
+ 1. `managed_waterfall`: product-managed evergreen waterfall lanes.
55
+ 2. `dashboard_evergreen`: dashboard-visible evergreen campaigns that are not in
56
+ the managed waterfall snapshot.
57
+ 3. `active_campaign`: regular active campaigns ranked into a deterministic
58
+ laneChain for non-evergreen refill planning.
59
+
60
+ If no lane family has refillable campaigns, report `no_refillable_campaigns`.
61
+ If the user lacks membership on a requested workspace, report the structured
62
+ `workspace_access` blocker with the workspace id and journal path.
63
+
64
+ ## G2 Refill Ladder
65
+
66
+ The planner chooses from this locked rung order:
67
+
68
+ 1. `start_campaign`: a paused selected lane has scheduler-ready supply but must
69
+ be live before the scheduler can pick it up.
70
+ 2. `approve_messages`: generated rows are ready for a bounded approval step.
71
+ 3. `wait_for_active_work`: enrichment, generation, import, or preparation is
72
+ already active, so the next honest action is to wait for that work to finish.
73
+ 4. `enrich_more`: exact-set enrichment can close the current ready gap.
74
+ 5. `reconcile_source_copy`: same-source rows exist and can be copied without
75
+ changing source family or source fingerprint.
76
+ 6. `add_leads_same_source`: the same source path can add bounded new supply.
77
+ 7. `paid_lane_fallback`: paid InMail is blocked or below threshold, so the same
78
+ waterfall can fall back to an existing supported lane.
79
+ 8. `next_campaign`: the current lane is exhausted, cooling down, pinned away, or
80
+ unsafe, and the next surviving campaign lane should be inspected.
81
+ 9. `wait_for_scheduler`: ready or projected supply covers the target, and only
82
+ scheduler pickup remains.
83
+ 10. `done`: the sender or lane is complete for the selected target window, a
84
+ scheduler cap makes additional preparation unnecessary, or
85
+ `no_refillable_campaigns` is the honest terminal.
86
+
87
+ Forward-only lane rule: a lane can move to a later rung or a later surviving
88
+ campaign, but the dry-run packet must not jump backward to invent work that the
89
+ facts do not support. Pinned-campaign rule: a pinned campaign stays selected
90
+ until the planner proves a blocker, cooldown, exhaustion, or safer next lane.
91
+ Capped-is-complete rule: when scheduler capacity is lower than the requested
92
+ target and ready/projected coverage satisfies that cap, report `done` with the
93
+ cap reason. Honest-itinerary rule: show what was checked, what was skipped, and
94
+ why; never hide uncertainty behind a confident source recommendation.
95
+
96
+ Guardrails: no campaign creation, no provider-family switch, no threshold
97
+ lowering, no scheduler writes, no launch/send/archive/delete, no
98
+ brief/filter/message/sequence/sender mutation, no message preparation, no
99
+ message approval, no paid InMail credit refresh, no source mutation, no row
100
+ queueing, and no campaign status change.
101
+
102
+ ## Journal
103
+
104
+ `get_refill_plan_v2` writes a local dry-run journal unless `journal:false` is
105
+ passed. Read the returned `journalPath` from the tool result and include it in
106
+ the report. The journal contains bootstrap, plan, and terminal sections plus an
107
+ index line under the run journal directory. If the tool returns
108
+ `journalPath:null` with a `journalWriteFailed` warning, report the warning and
109
+ continue with the dry-run packet; do not retry by writing local files yourself.
110
+
111
+ ## Report Contract
112
+
113
+ Completion means packet reviewed and journal written. Merely calling
114
+ `get_refill_plan_v2` is not completion proof.
115
+
116
+ Report these facts:
117
+
118
+ - workspace id and selected sender scope;
119
+ - plan revision and state revision;
120
+ - selected campaign, lane source, and laneChain per sender;
121
+ - chosen rung and dry-run action queue;
122
+ - itinerary, skipped lanes, blockers, cooldowns, and warnings;
123
+ - `no_refillable_campaigns` terminals and `workspace_access` blockers;
124
+ - journal path;
125
+ - side effects proof, which must show all false values.
126
+
127
+ Stop after the report. This workflow never executes the action queue.
@@ -0,0 +1,266 @@
1
+ {
2
+ "version": "v1.0",
3
+ "workflow": "refill-sends-v2-workflow",
4
+ "principle": "Plan refill sends v2 as a read-only dry-run with zero mutations across managed_waterfall, dashboard_evergreen, and active_campaign lane sources.",
5
+ "laneSources": ["managed_waterfall", "dashboard_evergreen", "active_campaign"],
6
+ "terminalReasons": ["done", "no_refillable_campaigns"],
7
+ "blockers": ["workspace_access"],
8
+ "enumeratedRungs": [
9
+ "start_campaign",
10
+ "approve_messages",
11
+ "wait_for_active_work",
12
+ "enrich_more",
13
+ "reconcile_source_copy",
14
+ "add_leads_same_source",
15
+ "paid_lane_fallback",
16
+ "next_campaign",
17
+ "wait_for_scheduler",
18
+ "done"
19
+ ],
20
+ "requiredBootstrap": [
21
+ {
22
+ "tool": "get_auth_status",
23
+ "purpose": "Confirm MCP auth before reading workspace or plan facts."
24
+ },
25
+ {
26
+ "tool": "get_active_workspace",
27
+ "purpose": "Resolve explicit workspace evidence when the request did not provide workspaceId."
28
+ },
29
+ {
30
+ "tool": "refill_sends_v2",
31
+ "requiredValues": {
32
+ "workspaceId": "{workspaceId}"
33
+ },
34
+ "requiredOutput": [
35
+ "readOnly true",
36
+ "approvalContract says Phase 86 handles execution"
37
+ ]
38
+ },
39
+ {
40
+ "tool": "get_subskill_prompt",
41
+ "requiredValues": {
42
+ "subskillName": "refill-sends-v2-workflow"
43
+ },
44
+ "mustReadUntil": {
45
+ "hasMore": false
46
+ }
47
+ },
48
+ {
49
+ "tool": "get_subskill_asset",
50
+ "requiredValues": {
51
+ "subskillName": "refill-sends-v2-workflow",
52
+ "assetPath": "core/flow.v1.json"
53
+ },
54
+ "mustReadUntil": {
55
+ "hasMore": false
56
+ },
57
+ "validation": {
58
+ "workflow": "refill-sends-v2-workflow",
59
+ "versionPrefix": "v1",
60
+ "requiredTopLevelKeys": [
61
+ "states",
62
+ "gateOrder",
63
+ "enumeratedRungs",
64
+ "verification",
65
+ "laneSources",
66
+ "terminalReasons",
67
+ "blockers"
68
+ ]
69
+ }
70
+ },
71
+ {
72
+ "tool": "get_refill_plan_v2",
73
+ "requiredValues": {
74
+ "workspaceId": "{workspaceId}",
75
+ "intent": "auto"
76
+ },
77
+ "requiredOutput": [
78
+ "planRevision or workspace_access blocker",
79
+ "stateRevision",
80
+ "packet",
81
+ "journalPath",
82
+ "sideEffects"
83
+ ]
84
+ }
85
+ ],
86
+ "gateOrder": ["bootstrap", "plan", "report"],
87
+ "states": [
88
+ {
89
+ "id": "bootstrap",
90
+ "description": "Load the read-only command contract, workflow prompt, flow asset, and workspace facts.",
91
+ "allowedTools": [
92
+ "get_auth_status",
93
+ "get_active_workspace",
94
+ "list_workspaces",
95
+ "get_workspace",
96
+ "refill_sends_v2",
97
+ "get_subskill_prompt",
98
+ "get_subskill_asset",
99
+ "get_refill_plan_v2"
100
+ ],
101
+ "onEnter": [
102
+ {
103
+ "tool": "get_auth_status"
104
+ },
105
+ {
106
+ "tool": "refill_sends_v2",
107
+ "requiredFields": ["workspaceId"]
108
+ },
109
+ {
110
+ "tool": "get_subskill_prompt",
111
+ "requiredValues": {
112
+ "subskillName": "refill-sends-v2-workflow"
113
+ }
114
+ },
115
+ {
116
+ "tool": "get_subskill_asset",
117
+ "requiredValues": {
118
+ "subskillName": "refill-sends-v2-workflow",
119
+ "assetPath": "core/flow.v1.json"
120
+ }
121
+ }
122
+ ],
123
+ "transitions": {
124
+ "contract_loaded": "plan"
125
+ }
126
+ },
127
+ {
128
+ "id": "plan",
129
+ "description": "Call the read-only refill sends v2 dry-run planner exactly once for this invocation.",
130
+ "allowedTools": ["get_refill_plan_v2"],
131
+ "onEnter": [
132
+ {
133
+ "tool": "get_refill_plan_v2",
134
+ "requiredFields": ["workspaceId"],
135
+ "optionalFields": [
136
+ "intent",
137
+ "senderIds",
138
+ "runState",
139
+ "journal",
140
+ "journalNote"
141
+ ]
142
+ }
143
+ ],
144
+ "requiredOutput": [
145
+ "sideEffects all false",
146
+ "planRevision starts with pr1: unless blocker is workspace_access",
147
+ "journalPath reported",
148
+ "chosen evergreenRung is in enumeratedRungs",
149
+ "lane sources are managed_waterfall, dashboard_evergreen, or active_campaign",
150
+ "terminal can be no_refillable_campaigns"
151
+ ],
152
+ "allowedRungsSource": "enumeratedRungs",
153
+ "doNotAllow": [
154
+ "add_column",
155
+ "add_on_demand_leads",
156
+ "add_rubric_item",
157
+ "add_teammate",
158
+ "add_to_comment_campaign",
159
+ "add_to_connection_campaign",
160
+ "add_to_inmail_campaign",
161
+ "archive_campaign",
162
+ "attach_recommended_sequence",
163
+ "attach_sequence",
164
+ "bulk_enrich_with_prospeo",
165
+ "cancel_campaign_message_preparation",
166
+ "cancel_lead_import",
167
+ "capture_post_idea",
168
+ "check_rubric",
169
+ "commit_blueprint",
170
+ "confirm_harvest_job_companies",
171
+ "confirm_lead_list",
172
+ "confirm_prospeo_company_accounts",
173
+ "copy_sender_config",
174
+ "create_campaign",
175
+ "create_on_demand_campaign",
176
+ "create_on_demand_table",
177
+ "create_workspace",
178
+ "create_workflow_table",
179
+ "delete_column",
180
+ "delete_rubric_item",
181
+ "duplicate_campaign",
182
+ "enrich_with_prospeo",
183
+ "fill_campaign_horizon",
184
+ "get_or_create_direct_campaign_table",
185
+ "import_leads",
186
+ "load_csv_dnc_entries",
187
+ "load_csv_domains",
188
+ "load_csv_linkedin_leads",
189
+ "mark_post_published",
190
+ "migrate_flat_configs",
191
+ "pause_campaign",
192
+ "pause_direct_campaign",
193
+ "pause_on_demand_campaign",
194
+ "prepare_campaign_ab_test",
195
+ "queue_campaign_cells",
196
+ "queue_cells",
197
+ "record_campaign_review_batch",
198
+ "record_engage_proven_search",
199
+ "refill_sends",
200
+ "refresh_paid_inmail_credits",
201
+ "revise_message_template_and_rerun",
202
+ "save_domain_filters",
203
+ "save_hook_research",
204
+ "save_post_draft",
205
+ "save_rubrics",
206
+ "send_inbox_draft",
207
+ "send_inbox_manual_reply",
208
+ "set_active_workspace",
209
+ "set_campaign_waterfall_order",
210
+ "set_company_info",
211
+ "set_engage_state",
212
+ "set_engage_style_guide",
213
+ "set_headline_icp_criteria",
214
+ "set_sender_routing",
215
+ "setup_evergreen_campaigns",
216
+ "start_campaign",
217
+ "start_campaign_message_preparation",
218
+ "start_direct_campaign",
219
+ "start_on_demand_campaign",
220
+ "update_campaign",
221
+ "update_campaign_brief",
222
+ "update_cell",
223
+ "update_column",
224
+ "update_inbox_draft",
225
+ "update_post_draft",
226
+ "update_published_post_metrics",
227
+ "update_rubric_item",
228
+ "upsert_engage_tracked_person",
229
+ "upsert_rubric"
230
+ ],
231
+ "transitions": {
232
+ "packet_returned": "report",
233
+ "workspace_access": "report"
234
+ }
235
+ },
236
+ {
237
+ "id": "report",
238
+ "description": "Present packet, lane source, laneChain, itinerary, warnings, blockers, plan revision, and journal path; then stop.",
239
+ "allowedTools": [],
240
+ "onEnter": [
241
+ {
242
+ "action": "present_packet_itinerary_and_journal_path"
243
+ }
244
+ ],
245
+ "terminal": true
246
+ }
247
+ ],
248
+ "verification": {
249
+ "requiredProof": [
250
+ "sideEffects all false in get_refill_plan_v2 response",
251
+ "planRevision has pr1: prefix unless blocker is workspace_access",
252
+ "journalPath reported or journalWriteFailed warning surfaced",
253
+ "chosen evergreenRung belongs to enumeratedRungs",
254
+ "lane source belongs to managed_waterfall, dashboard_evergreen, active_campaign",
255
+ "laneChain recorded when active_campaign chain is selected",
256
+ "no_refillable_campaigns terminal reported when no lane is refillable",
257
+ "packet reviewed with itinerary and blockers"
258
+ ],
259
+ "notCompletionProof": [
260
+ "called get_refill_plan_v2 alone",
261
+ "action queue exists",
262
+ "ready rows alone",
263
+ "operator wants execution"
264
+ ]
265
+ }
266
+ }